--- title: "15万个访客,只有2%是人" description: "最多 60 人的内部网站,四个月来了 15 万个独立 IP。浏览器 UA 是自我介绍,行为指纹才是身份证——最后靠一个 Basic Auth 加三层拦截关门。中间还踩了个坑:nginx -t 通过了,站点却 404 了。" date: 2026-08-31T20:30:00+08:00 draft: false tags: - 安全 - 运维 - 日志分析 --- ## 背景 一个内部知识库站,最多 60 个人用。用户甩来一份 126MB 的 access log:「被爬虫滥用抓取了」。 四个月,50.3 万次请求,6.4GB 流量。 ## 第一层:明牌的爬虫 爬虫们其实很"诚实",UA 里自己写得清清楚楚: | 爬虫 | 总量 | 行为 | |------|------|------| | YisouSpider | ~3.5 万 | 5-6 月主力,反复抓同一批 css/js | | Bytespider | ~3.2 万 | 出了名的凶 | | PetalBot | ~2.9 万 | 当前日活第一,日均 200-400 次 | | bingbot | ~6600 | 规矩 | | MJ12bot / DotBot | ~8600 | 零价值的外链分析商 | 最壮观的是 GPTBot:某天单日 10,248 次,**占当天全站流量的 67%**——一天抓完整个站,然后消失。 自报爬虫的合计 12.9 万次(25.7%),吃掉 1.8GB(28%)。看起来故事到这里就该结束了:加 robots.txt、限个速、和爬虫共存。 ## 转折:一句话 用户补了一句:「浏览器 UA 也不一定是正常的,我们这个是内部网站,最多用户也就 60 人。」 重算: - 全站独立 IP:**150,195 个**。60 人 × PC + 手机,撑死 120 个。超了 **1250 倍** - 四个月 `POST /login`:**7 次**。而 `GET /login` 有 2,929 次——两千多次访问登录页,没一次真登录 - 最大的"浏览器"群体 Chrome/142,8.9 万次请求摊在 8017 个 IP 上,**人均 11 次**;对照真人办公网 IP,一个发了 3060 次 - Chrome 版本动物园:Chrome/75(2019 年)、/87、/89 还在"活跃浏览"——60 人的内部站,没人五年不升级浏览器 - 真人画像反而清晰:办公网固定出口,一个 IP 数百上千次/月;移动端全是钉钉内置浏览器 UA 结论:**"浏览器 UA"里的大多数,也是机器。** 真人流量只占 **2.1%**。 ## 关门,不是限流 公网站的思路是"与爬虫共存":robots.txt、限速、静态缓存。内部网站不用这么客气——**直接关门**。 站点已经加了 Basic Auth(60 个账号以内的场景,两行配置够用),再叠三层拦截: ```nginx if ($bad_bot_uf) { return 403; } # 14 条爬虫 UA if ($bad_ip_uf) { return 403; } # 21 条机房/扫描器网段 if ($request_uri ~* "^/(wp-admin|wp-content|wp-login|admin\.php)") { return 444; } ``` 注意顺序:403 放在 auth_basic **之前**——不让爬虫碰到认证弹窗,连试探账号的机会都没有。444 比 403 更狠:连接直接掐断,一个字节都不回。 上线实测:四个爬虫 UA 全部 403、机房 IP 全部 403、wp-login 返回 000(连接重置)、办公网真人 401 走正常认证。日志里立刻出现 403 和 444——机器们开始吃闭门羹。 ## 插曲:nginx -t 通过了,站点却 404 了 部署途中踩了个值得单独立传的坑。 往容器里改配置,`docker cp` 对挂载路径失效,改用管道写入。写完一查:`nginx -t` 显示 **syntax is ok**,reload 也没报错——**站点却全站 404 了**。 排查发现:配置文件被写成了 **0 字节**。nginx 面对一个空的 server 配置,回退到了 default server——语法检查当然通过,因为语法"没错",只是"你的站没了"。 > **`nginx -t` 只验证语法,不验证"还是不是你的站在应答"。** 变更前先备份,写完检查文件非空,reload 后立刻用真实 URL 验一遍。 ## 总结 1. **UA 是自我介绍,行为才是身份证**。爬虫伪装浏览器 UA 的成本是零,但 IP 池规模、请求频次分布、版本动物园这些指纹改不掉 2. **内部网站的姿势是关门,不是斗智斗勇**。60 人的站,认证一步到位,比任何限流规则都省心 3. **401 vs 403 的顺序也是设计**。让爬虫先吃 403,认证机制保持神秘 4. **测试通过 ≠ 服务正常**。语法检查、单元测试都只回答"代码对不对",不回答"跑的还是不是原来那个服务" > 50 万条日志里最有价值的一句话,是用户那句"我们最多 60 人"。数据的答案,常常就藏在"常识应该是什么样"和"实际是什么样"的差距里。 --- *本文已脱敏,不含真实域名、IP、账号或凭证。*