服务器一夜被刷爆,我交了 387 块学费才学会一句话:封 IP 不如识 IP

0 阅读10分钟

故事从一条短信开始

那天早上 7 点 48 分,我被一条短信震醒。

【XX 云】尊敬的用户,您的账户余额低于预警阈值,请及时充值以保证服务正常运行。

我揉着眼睛点开后台,倒吸一口冷气:

  • 流量包:消耗 98%
  • CDN 用量:是平时的 47 倍
  • 总账单:已扣 387 元(前一天我的账单是 4 块 2)

这是一个我用爱发电了大半年的小工具站,平时 DAU 不到一千。它不可能一夜之间烧掉我半个月的咖啡钱。

打开 Nginx 的 access.log,瞬间懂了——有人在刷我的接口,每秒上百次。

log_screenshot_v2.png

那一天我熬到傍晚,终于把流量打回正常水平。这篇文章不是"反爬教程",而是一份踩坑实录:从我一开始用最朴素的 ban IP 被打脸,到后来才搞懂"封 IP 不如识 IP"——这中间我交的智商税,希望能省你一些。


一、最朴素的第一反应:封 IP

打开日志,最先映入眼帘的是这样的请求:

123.45.67.89 - - [08:14:23] "GET /api/search?q=xxx HTTP/1.1" 200 1247
123.45.67.89 - - [08:14:23] "GET /api/search?q=yyy HTTP/1.1" 200 1183
123.45.67.89 - - [08:14:24] "GET /api/search?q=zzz HTTP/1.1" 200 1294
...

清一色的同一个 IP,每秒打十几次 /api/search

简单粗暴,加进 Nginx 黑名单:

deny 123.45.67.89;

nginx -s reload,搞定。

10 秒后,日志里冒出来另一个 IP,频率一模一样。

再封。

20 秒后,又来一个。

我意识到不对劲——这哥们手里有一IP。我那时还以为自己发现了什么大秘密:原来真有这种"分布式爬虫"。

💡 后来我才知道: 现在网上随便一个住宅代理服务商,1000 个 IP 包月只要几十块,按量付费的甚至几毛钱一个新 IP。封 IP 在 2025 年这个时间点,已经是性价比最低的反爬手段。 你封一个他换一个,你的 nginx.conf 越来越长,他的成本几乎为零。


二、第二招:限流。然后我误伤了真用户

封 IP 不行,那就限流——同一个 IP 一分钟超过 60 次就 429。

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=60r/m;

部署上去十分钟,问题来了。

真实用户开始投诉打不开页面。

排查之后发现两类误伤:

  1. 公司局域网用户——一个公司几十号人共用一个公网出口 IP,一限就误伤一片。
  2. 手机 4G 切 WiFi 的用户——运营商的 NAT 池里几百号人共用 IP,刷两下就被限。

而那个爬虫呢?它的 IP 池里每个 IP 一分钟也就请求十几次,根本触不到我设的阈值

我第一次意识到一个反直觉的事实:

🎯 基于 IP 频率的限流,只能拦住"懒爬虫"。一个稍微懂点事的爬虫,会用 IP 池把每个 IP 的请求频率控制得比真人还低。

到这一步,我已经被打了两个耳光。账单还在涨。


三、转折点:我开始研究"这些 IP 都是什么 IP"

冷静下来之后,我决定换个思路:与其拦请求,不如先搞清楚来的人是谁。

我把日志里前一小时所有疑似爬虫的 IP 抠出来,去重,得到大约 800 多个 IP。然后我做了一件之前从来没做过的事——逐个查这些 IP 的"身份"

这一查,新世界的大门打开了。

我用了 BiuPing 的 IP 信誉查询(最近他们刚上的功能,免费)抽样查了几十个,发现这些 IP 的画像高度一致:

维度爬虫 IP 表现真实用户 IP 表现
类型90% 标记为「数据中心 / IDC」95% 是「住宅 / 移动网络」
代理标记大量被识别为代理/VPN几乎不带代理标记
黑名单命中多数在 1-3 个威胁库里被举报过极少命中
风险评分平均 70+ 分(满分 100,越高越危险)普遍在 5 分以下
国家归属集中在几个海外机房友好型地区中国大陆为主

我把这个表打印出来贴在显示器旁边。这是这次踩坑最大的收获。

comparison_card.png


四、一个 IP 能告诉你的事,远比你想象的多

我之前以为 IP 就是个数字,最多能查到运营商和省份。后来才发现,每一个 IP 在互联网上都有一份"档案",包括:

1. 它是住宅 IP 还是机房 IP

  • 住宅 IP:电信/联通/移动分配给家庭宽带、手机的 IP,背后大概率是真人。
  • 机房 IP(IDC/Datacenter):阿里云、腾讯云、AWS、DigitalOcean 这些数据中心的 IP。正常用户不会从机房 IP 访问你的网站——除非他自己在云服务器上写了脚本。

🧠 划重点: 一个看起来是中国某城市的 IP,它的归属地"信息"和"类型"可以完全不一样。机房 IP 也有归属地(机房在哪它就显示哪),但类型字段会写明这是 IDC。只看归属地不看类型,会被骗到。

2. 它是不是已知的代理 / VPN / Tor 出口

全球有公开维护的代理列表、VPN 出口列表、Tor 出口节点列表。一个 IP 如果出现在这些列表里,访问你的业务时应当被多看两眼——不是要直接 ban,但至少应该提高它的"可疑度评分"。

3. 它是不是被举报过

像 AbuseIPDB、Spamhaus、Project Honey Pot 这些威胁情报库里,每天有大量 IP 因为发垃圾邮件、暴力破解、扫端口、DDoS 被全球受害者举报。一个被几十个独立站点举报过的 IP,几乎不可能是来你这看小说的真用户。

4. 综合风险评分

把上面这些维度加权得到一个 0-100 的分数。我自己的经验值是:

  • 0-30:普通用户,放行
  • 30-60:灰色地带,加滑块/人机验证
  • 60+:高风险,直接拒绝或返回假数据

五、改造方案:从"封"到"识"

想清楚之后,我把 Nginx 那一坨 deny 全删了,重写了风控逻辑。架构大概是这样:

用户请求
    ↓
Nginx → 转发到风控网关 (Lua/Go 写的小服务)
    ↓
风控网关查询:
    ├─ 这个 IP 之前来过吗?(本地 Redis 缓存)
    │   ├─ 是 → 用缓存的信誉分
    │   └─ 否 → 查询 IP 信誉数据,结果回写 Redis(TTL 24h)
    ↓
根据信誉分决策:
    ├─ < 30   → 直接放行
    ├─ 30-60  → 在前端弹滑块/人机验证
    └─ ≥ 60   → 返回 403 或假响应
    ↓
真实业务接口

arch_diagram.png

几个关键设计:

1. 必须做缓存。 IP 信誉数据不是每次请求都现查的,那样性能扛不住、调用成本也吃不消。第一次见到的 IP 才查,查完结果丢 Redis 缓存 24 小时。绝大多数请求都命中缓存,性能几乎没影响。

2. 灰度放行,别一刀切。 60 分以上直接 ban,但 30-60 分这一段千万别 ban——这一段里混着大量公司 NAT 出口 IP、机场 WiFi、公共 WiFi。给它们弹个滑块即可,体验损失最小。

3. 假响应比 403 好用。 对评分极高的恶意 IP,别返回 403——这等于告诉对方"我识破你了",对方会立刻换策略。返回一个看起来正常的、但数据是假的响应,让爬虫把脏数据吃下去。这招对内容站尤其有效。

4. 不要信任前端 IP 字段。 一定要从 Nginx 透传的 X-Forwarded-For 里拿真实 IP,且只信任最左边那个(最靠近用户的)。这一步搞错的话,你拿到的全是 Nginx 自己的 IP,整个风控就废了。

部署完之后第二天,账单回到 5 块钱以内,CPU 也安静了。

事后我跑了一下数据:那一波"攻击"里,91% 的请求来自机房 IP,6% 来自已知代理池,剩下 3% 是漏网之鱼。 如果我一开始就识别 IP 类型而不是封 IP,那 387 块学费可以省下来。


decision_flow.png

六、把这套东西用到日常运维里

后来我意识到,IP 信誉这件事不只在"被刷爆"的时候有用,平时也用得上:

1. 注册接口保护。 注册接口是垃圾账号重灾区。在注册时拦截一下风险 IP,能干掉 80% 的批量注册脚本。

2. 评论 / 内容发布。 防垃圾评论,传统是接谷歌 reCAPTCHA。但 reCAPTCHA 在国内访问慢、对真用户体验差。先做一道 IP 信誉过滤,可以让 90% 的真用户绕过验证码,体验一下子上去了。

3. 排查异常订单。 电商业务里,用机房 IP 下单的,几乎 100% 不是真实买家。要么是黄牛脚本,要么是测试,要么是欺诈。这个维度比"同一收货地址下多单"更早一步。

4. 调试自己业务的访问情况。 写完一个新接口,想知道全国各地访问它的速度、是否有路由问题,可以先用 BiuPing 多节点 Ping 跑一轮看延迟分布;想知道接口在各地的 HTTPS 握手有没有问题,用 网站测速 看瀑布流。这些跟反爬不直接相关,但属于平时排查"为什么有的用户慢"的常用手段。


七、写给独立开发者的几句真心话

我不是搞安全出身的,这次是被打懵了之后现学现卖。如果你也是写小工具站、独立产品的开发者,下面几句肺腑之言:

1. 永远开账单告警。 不是流量告警,是账单告警。流量告警可能在你睡觉的时候不痛不痒,账单告警一定会吵醒你。早一小时醒来,可能就少烧几百块。

2. 接口加缓存比加风控更便宜。 一个频繁被打的接口,第一反应应该是"它的结果能不能缓存"。能缓存的话,被刷一万次也只是把缓存读爆,源站根本不会慌。

3. 别给 GET 接口设计成"参数随便变"。 我那个 /api/search?q=xxx 之所以被针对,就是因为 q 一变 URL 就变,CDN 缓存命中率为零。改成"q 标准化 + 限定字符集"之后,命中率从 0% 升到 78%,被刷的成本对方扛不住就放弃了。

4. 保留 1-2 周的完整日志。 你不知道哪天会需要它。这次复盘我能写出来,全靠当晚没急着 logrotate。

5. 对 IP 这件事多一点敬畏。 一个 IP 不是一个数字,它身后有一整张档案。学会识别 IP,比学会封 IP 重要得多。


八、最后

写这篇的时候我又翻了一下当时的账单截图,387 块。

看起来不多,但对一个用爱发电的独立项目来说,等于直接吃掉两个月的服务器钱。这次之后我养成了一个习惯:每接入一个新接口、上一个新功能之前,先想清楚"如果有人恶意刷它,我会损失什么"。想清楚了再上线。

如果你也在做小项目、独立站、API 服务,这篇文章里的坑你可能早晚都会踩。不如先把它收藏了,下次半夜被账单短信吵醒的时候,至少还有人陪你一起骂街。

最后留个开放问题:

你做项目的时候,被薅得最惨的一次是怎样?后来怎么解决的?

评论区聊聊,让那些没踩过坑的同行也长长见识 👀


文中提到的工具:

都在 biuping.com,免费,无需注册。我自己的开发书签里钉了大半年了。