反爬规则上线前要查什么?一份自查清单

反爬规则拦不住爬虫,最多算白干;拦住自己人,才是真事故。搜索引擎蜘蛛被误伤会掉收录,合作方接口被拦会掉服务,监控探针被拦会掉告警,而这三种损失往往要等几天才暴露。本文用 9 个问答给出一份反爬规则上线前的自查清单。

Q:反爬规则上线前,最容易出的问题是什么?

  • 不是拦不住,而是拦错了却没人发现。三类误伤最常见:
  • 误伤搜索引擎蜘蛛:收录和抓取量悄悄下滑,等发现时已经掉了一批关键词排名。
  • 误伤合作方与自有系统:支付回调、数据接口、监控探针、拨测节点被拒,业务和告警同时出问题。
  • 误伤真实用户:公司出口、客户办公网、运营商大 NAT 出口被整片封禁。
  • 共同点是故障静默:日志里全是 403 和 429,但没人盯着看。所以上线前的重点,是先把「怎么发现拦错」和「怎么快速撤回」准备好。

Q:怎么先做到只记录不拦截?

  • 任何新规则都应该先跑观察模式,取一个完整周的数据,覆盖爬虫抓取高峰和业务大促窗口。
  • 做法有两种,按你的拦截位置选:
  • 规则层直接指定观察:Nginx 的限流支持只记录不拒绝。
  • 打标记而不拒绝:用变量给可疑请求打上标记,写进响应头和日志,前端与日志先照常工作。
# 1) 限流只记录不拒绝(观察期专用)
limit_req_dry_run on;

# 2) 按 UA 打标记,先不拒绝:加到日志里观察命中量
map $http_user_agent $bot_flag {
    default                      0;
    ~*(python-requests|scrapy|curl|wget|headlesschrome)  1;
}
add_header X-Bot-Flag $bot_flag always;
add_header X-Limit-Flag $limit_req_status always;
  • 观察期的验收标准:规则命中量稳定、被命中对象里能明确区分出「该拦」和「不该拦」,再进入下一步。

Q:白名单要列哪些,顺序怎么排?

  • 白名单不是可选项,漏一项就可能是一次线上事故。建议逐条对照:
  • 搜索引擎蜘蛛的真实来源 IP 段;自有办公网、机房、跳板机与 CI 构建机;监控探针与拨测节点;压测出口;支付与短信等第三方回调;有授权协议的采集方;CDN 回源节点。
  • 顺序上牢记一点:Nginx 的 allow 与 deny 按出现顺序从前到后匹配,命中即结束。所以白名单必须写在通用拦截规则前面。
# 白名单统一放在文件最上方,命中即 return
geo $whitelist {
    default        0;
    10.0.0.0/8     1;
    203.0.113.0/24 1;   # 压测出口
    198.51.100.7   1;   # 监控探针
}
map $whitelist $limit_key {
    1  "";
    0  $binary_remote_addr;
}

server {
    # 先放行,再拦截
    allow 10.0.0.0/8;
    allow 203.0.113.0/24;
    deny  all;
}
  • 需要注意:空 key 的请求通常不计入限流,这正是白名单的常见写法,上线前请在你们实际使用的 Nginx 版本上验证一次。

Q:怎么确认来访的搜索引擎蜘蛛是真的?

  • 只看 User-Agent 一定被绕过,UA 是客户端随手就能改的字符串。正向解析证明不了身份,必须做反向解析:
# 由来访 IP 反查域名,再正向查回来比对,两次一致才算真蜘蛛
dig -x 1.2.3.4 +short
# 输出应形如 crawl-1-2-3-4.baidu.com / crawl-1-2-3-4.googlebot.com

# 正向确认:解析结果必须能回到同一个 IP
dig +short crawl-1-2-3-4.baidu.com
  • 再叠加官方公布的 IP 段清单做二次校验,两者都过才放行。
  • 提醒一句:蜘蛛 IP 段会被转卖和冒用,通过反解校验只能挡掉大部分,长期还要看抓取行为是否合理(抓取频率、路径分布、是否遵守 robots 协议)。

Q:多层规则打架,怎么快速排查?

  • 反爬规则通常分散在 CDN、WAF、Nginx 三层,最常见的现象是只看一层配置怎么都找不到拦截来源。
  • 四条排查路径:
  • 看响应头指纹:不同层的拒绝返回的 Server、状态码和自定义头不一样,先判断是哪一层拒绝的。
  • 看 nginx 生效后的完整配置:nginx -T 输出的是合并与 include 之后的真实配置,比逐个看文件可靠。
  • 核对 location 优先级:精确匹配 = 最高,其次是 ^~ 前缀,再是正则,最后是普通前缀。规则写在低优先级段里可能永远不生效。
  • 检查 return 与 rewrite 的顺序:return 会在早期阶段直接结束请求,写在它后面的规则等于不存在。
# 抓真实拦截响应,看是哪一层拒绝、返回什么
curl -sI -o /dev/null -w '%{http_code} %{time_total}\n' -A 'python-requests/2.31' https://www.example.com/

# 打印合并后的完整配置,确认规则真的在了、顺序对不对
nginx -T 2>/dev/null | grep -n -A3 -E 'limit_req|limit_conn|deny|allow'

Q:灰度上线的节奏怎么安排?

  • 建议三段式,每段之间留出观察窗口:
  • 第一段观察:跑 7 天,只记录不拦截,产出一份命中对象清单。
  • 第二段小范围:只对最明确的一类(例如 UA 完全匹配的扫描器)真正拒绝,观察 2 至 3 天。
  • 第三段全量:确认无异常后放开到行为类规则。避开大促、发版和投放窗口,别在流量高峰改规则。
  • 对拿不准的规则,可以只在小流量入口或非核心路径上先生效,核心链路留到第二天。

Q:上线后必须盯哪些指标?

  • 四个指标能覆盖绝大多数误伤:
  • 被拒比例:403 与 429 占全部请求的比例,超过日常基线就要看是谁在被拒。
  • 真实蜘蛛抓取量:在站长平台看抓取频次与收录数,比在服务器上数 UA 更准。
  • 业务成功率:下单、支付、登录等核心接口的成功率不能被反爬规则影响。
  • 告警与探针存活:监控探针一旦被拦,你会连告警都收不到,这是最危险的静默故障。
# 每天扫一遍:被拒请求的 TOP 来源与 TOP 路径
grep -E ' 40[13] | 429 ' access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
grep -E ' 40[13] | 429 ' access.log | awk '{print $7}' | sed 's/?.*//' | sort | uniq -c | sort -rn | head -20

Q:出问题了怎么一键回滚?

  • 回滚速度取决于上线前有没有把规则拆开:
  • 把整套反爬规则放进独立文件,主配置里只留一行 include,回滚就是注释掉这一行再 reload。
  • 保留上一版配置副本,改完先用 nginx -t 校验语法,再 reload。
  • 记录每一条规则的负责人、上线时间和到期日,避免临时规则半年后还挂在线上。
# 主配置只保留一行
include /etc/nginx/conf.d/anti-scraping/*.conf;

# 回滚三步
sed -i 's|^include .*anti-scraping.*|# &|' /etc/nginx/nginx.conf
nginx -t && nginx -s reload
nginx -T 2>/dev/null | grep -c 'limit_req_zone'   # 应为 0

Q:还有什么补充建议?

  • 把这份清单固化成上线流程:观察期数据齐全、白名单逐条核对、反解校验蜘蛛、灰度分三段、指标有基线、回滚一行生效,六项缺一项就别上线。
  • 规则宁可少而稳,不要一次上几十条。规则越多,冲突与误伤的组合越多,排查成本呈指数上升。
  • 每季度做一次外部视角复查:从站外扫一遍自己的防护规则、核对白名单是否还准确,比事后救火便宜得多。