Files
blog/content/posts/two-percent-human.md

4.5 KiB
Raw Permalink Blame History

title, description, date, draft, tags
title description date draft tags
15万个访客,只有2%是人 最多 60 人的内部网站,四个月来了 15 万个独立 IP。浏览器 UA 是自我介绍,行为指纹才是身份证——最后靠一个 Basic Auth 加三层拦截关门。中间还踩了个坑:nginx -t 通过了,站点却 404 了。 2026-08-31T20:30:00+08:00 false
安全
运维
日志分析

背景

一个内部知识库站,最多 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 人。」

重算:

  • 全站独立 IP150,195 个。60 人 × PC + 手机,撑死 120 个。超了 1250 倍
  • 四个月 POST /login7 次。而 GET /login 有 2,929 次——两千多次访问登录页,没一次真登录
  • 最大的"浏览器"群体 Chrome/1428.9 万次请求摊在 8017 个 IP 上,人均 11 次;对照真人办公网 IP,一个发了 3060 次
  • Chrome 版本动物园:Chrome/752019 年)、/87、/89 还在"活跃浏览"——60 人的内部站,没人五年不升级浏览器
  • 真人画像反而清晰:办公网固定出口,一个 IP 数百上千次/月;移动端全是钉钉内置浏览器 UA

结论:"浏览器 UA"里的大多数,也是机器。 真人流量只占 2.1%

关门,不是限流

公网站的思路是"与爬虫共存":robots.txt、限速、静态缓存。内部网站不用这么客气——直接关门

站点已经加了 Basic Auth(60 个账号以内的场景,两行配置够用),再叠三层拦截:

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 okreload 也没报错——站点却全站 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、账号或凭证。