Nginx 防爬虫和 CDN 防护怎么配合使用?
CDN在边缘按IP、频率、UA等初筛,Nginx在源站结合登录态、令牌和访问行为精细识别;配合前须用realip仅信任CDN回源段还原真实IP,否则限流会误伤全站,且不可信任任意XFF。
结论:CDN 负责在边缘做范围较大的初步过滤(按 IP、频率、UA、JS 挑战),Nginx 负责在源站做精细判断(登录态、令牌、访问路径序列),两层配合的前提是先做真实 IP 还原;否则 Nginx 的限流会把 CDN 回源节点当成一个客户端,直接把全站限制住。
为什么 Nginx 限流一开就和 CDN 打架?
因为开启 CDN 后,$remote_addr 拿到的是 CDN 回源节点的 IP,不是用户真实 IP;如果不还原,limit_req_zone $binary_remote_addr 的 key 只剩几个节点 IP,几十万用户会共用同一个限流桶。
修复方式是配置 ngx_http_realip_module,只信任 CDN 回源段:
set_real_ip_from 10.0.0.0/8; # 换成 CDN 厂商公布的回源段
set_real_ip_from 172.16.0.0/12;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
必须只写 CDN 的回源网段,不要写 0.0.0.0/0。X-Forwarded-For 是客户端可伪造的请求头;一旦全信任,攻击者只要自己加一个假 XFF 就能绕过限流,等于没做防护。上线后请检查 access_log 里的 $remote_addr 是否已是真实公网 IP,这是所有后续策略的基础。
CDN 层应该承担哪些防护?
CDN 层的定位是“用低成本规则挡掉大部分”请求,只把可疑流量回源;判断依据是 IP、频率、UA、Referer,不涉及业务状态。
可落地的四项:一是单 IP 频率限制,建议 60 秒 300 次页面请求;二是 UA 黑名单,拦截 python-requests、scrapy、Go-http-client 等默认 UA;三是 Referer 防盗链,只允许本站域名引用静态资源;四是静态资源缓存,把图片、CSS、JS 的缓存命中率提高到 90% 以上,爬虫抓这些资源时完全不消耗源站。带 JS 挑战或验证码的 Bot 管理功能也放在这一层,因为它在边缘执行,源站零开销。
Nginx 层怎么识别伪装成浏览器的爬虫?
只靠 UA 判断一定会被绕过;UA 一行就能改。源站要用“行为特征 + 业务特征”来判断,而这些特征 CDN 通常拿不到。
三个可用的信号:请求头缺失(正常浏览器一定带 Accept-Language 和 Accept,脚本常常只带 UA);Cookie 为空却直接请求详情页;访问序列异常(只抓详情页,从不请求 CSS/JS)。用 map 把可疑 UA 映射成限流 key,再分层限速:
limit_req_zone $binary_remote_addr zone=html:20m rate=2r/s;
map $http_user_agent $bot_flag {
default 0;
"" 1;
~*(python-requests|scrapy|curl|wget|Go-http-client) 1;
}
server {
location / {
limit_req zone=html burst=30 nodelay;
if ($bot_flag) { return 444; }
}
}
return 444 是 Nginx 的非标准状态码:直接断开连接、不返回响应体,比返回 403 省带宽,也让脚本难以判断自己是被封还是网络故障。注意 if 在 location 里只适合这种简单 return,不要在里面写 proxy_pass。
两层的阈值怎么设置才不重复拦截?
原则是 CDN 阈值放宽、源站阈值收紧:CDN 挡“明显是机器”的流量,Nginx 挡“看起来像人但行为不对”的流量;让 CDN 的频率阈值保持在 Nginx 的 2 到 3 倍。
具体做法:CDN 侧按 300 次/分钟告警或拦截,Nginx 侧 rate=2r/s 配合 burst=30 nodelay,即允许 30 个突发请求后按每秒 2 个放行。这样正常用户翻页、加载资源不会被 CDN 误杀,而持续高频抓取一定会在源站被限速。再加一条回传机制效果更好:Nginx 记录被 444 的 IP,按 5 分钟窗口聚合,超过 20 次的 IP 通过 CDN 厂商 API 或控制台加入边缘黑名单,把防护前移到边缘。
上线前要验证什么?
三项必测:用 curl -H "X-Forwarded-For: 1.2.3.4" 请求源站,确认伪造的 XFF 不生效;确认 access_log 中记录的是真实客户端 IP;用压测工具模拟单 IP 高频请求,确认返回 444 或 503 而不是整站不可用。
灰度顺序建议先开 CDN 的频率限制(只告警不拦截)观察 3 天,再加 Nginx 限流,最后开启 444 拦截和 IP 回传。这样每一步出问题都能定位在哪一层。
总结:这套配合的核心是“边缘粗筛 + 源站精判 + 真实 IP 兜底”,三层缺一不可;部署前先在 access_log 里确认 $remote_addr 是真实用户 IP,再按 CDN 阈值为 Nginx 的 2 到 3 倍配置限流,最后把源站判定的恶意 IP 回传到边缘,形成闭环。
转载请注明出处,版权归原作者所有。