反爬合规怎么把握?拦截手段的边界在哪

拦得太松爬虫把站拖垮,拦得太狠又可能越界。反爬合规的关键不在要不要拦,而在用什么手段拦、留什么数据、误伤了怎么补救。本文用 10 个问答讲清拦截手段的边界、指纹与日志的处理方式,以及误封后的申诉通道该怎么给。

Q:反爬本身合法吗,为什么会扯上合规问题?

  • 拦截自动化流量本身没有问题。站点有权决定谁能访问、以什么频率访问,这属于正常的资源保护。
  • 出问题的地方几乎都在手段上,不在目的上。三类高风险做法:为了识别爬虫去采集与业务无关的设备信息;把拦截做成黑箱,误封了连申诉入口都没有;对不同来源返回内容不一致却不做任何说明。
  • 判断标准可以简化成一句:你采集的信息,是否超出了「判断这次请求是不是人」所必需的范围。
  • 这一条对 B 端站点更敏感。企业客户被误封一次,损失往往比一年的防护费用更高,而且他不会再给你第二次机会。

Q:哪几种拦截手段最容易越界?

  • 过度指纹:把 canvas、WebGL、字体列表、屏幕参数、硬件并发数拼成一个长期不变的设备 ID。拼得越多越像在识别具体设备,而不是在识别行为。
  • 注入式探测:在页面里塞一大段采集脚本,拖慢首屏,采集范围又不对用户说明。
  • 内容差异化返回:对疑似爬虫返回不同的价格、库存或联系方式。这既是搜索引擎明确反对的做法,也可能构成对消费者的差别对待。
  • 整段拉黑:一个 IP 命中就把整个 /24 段封掉,连带封掉同机房大量无关站点。
  • 全站强制人机验证:为了拦爬虫让所有真实用户反复过验证码,转化率掉下来,本质是把防护成本转嫁给了用户。
  • 共同点:收益归防护方,代价由无关的人承担。这类设计迟早会收到投诉。

Q:采集访问者指纹,边界到底在哪?

  • 四条可执行的原则:最小必要(只取判定需要的维度)、去标识(落库前哈希,不与账号身份长期绑定)、短留存(判定完成即降精度或删除)、不跨站(不做跨域追踪,不接第三方画像)。
  • 做法上,把完整 UA 原文换成粗粒度分类,就已经能满足绝大多数判定需求:
# 只生成粗粒度分类,不拼接完整 UA 原文
map $http_user_agent $ua_class {
    default            'other';
    ~*curl             'cli';
    ~*python           'cli';
    ~*go-http-client   'cli';
    ~*bytespider       'bytespider';
    ~*baiduspider      'baiduspider';
}

# 日志只落分类结果,不落完整 UA 与完整 query
log_format sec '$remote_addr - [$time_local] "$request_method $uri" '
               '$status $ua_class $request_time';
  • 提醒一句:URL 里的查询参数经常比 UA 更敏感。手机号、订单号、token 都可能出现在 query 里,记录完整 URI 等于把个人信息写进了技术日志。

Q:访问日志能留多久,怎么留才不出事?

  • 字段上做减法:保留 IP、时间、方法、去掉 query 的路径、状态码、UA 分类、耗时。不记录手机号、证件号、支付参数、登录态。
  • 期限上做约定:安全审计类日志按需设定(常见做法是六个月以内),业务分析类日志更短。到期自动清理,不要默认永久保留。
  • 用 logrotate 把「轮转 + 压缩 + 清理」一次性配好,比事后手工删靠谱得多:
/var/log/nginx/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    sharedscripts
    postrotate
        [ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
    endscript
}
# 兜底:清掉超期的压缩包
find /var/log/nginx -name '*.gz' -mtime +30 -delete
  • 只要日志里出现了可定位到具体个人的信息,它就不再是单纯的「技术日志」,访问权限也要跟着收紧。

Q:误封了正常用户,申诉通道该怎么给?

  • 被拦的页面上必须写清三件事:为什么被拦、怎么恢复、找谁。只返回一个空白 403,用户只会直接关站。
  • 三个最低要求:可自助解封(验证通过即放行)、有可提交的工单入口、有明确的处理时效。
error_page 403 429 /blocked.html;
location = /blocked.html {
    internal;
    root /usr/share/nginx/html;
    add_header Retry-After 60;
}

# 自助解封入口:只接受 POST,验证逻辑放后端
location = /unblock {
    limit_except POST { deny all; }
    proxy_pass http://127.0.0.1:8081/unblock;
    proxy_set_header X-Real-IP $remote_addr;
}
  • 申诉数据要能回流到规则里。同一类误封被申诉三次以上,说明规则本身有问题,该改阈值而不是继续让用户申诉。

Q:封 IP 会不会一不小心封掉一大片人?

  • 会,而且比想象中常见。运营商大 NAT、企业出口、校园网、移动网络出口池,一个 IP 后面可能是几千上万人。
  • 四条降误伤规则:多维同时命中才封(IP 加 UA 加路径规律加频率)、封禁时长分级(从 5 分钟起,看复犯再加)、白名单永远优先、先观察再拦截。
  • 技术上优先用带自动过期的封禁,别写进永久 deny 文件:
# 5 分钟自动过期,避免长期误封
ipset create cc_block hash:ip timeout 300 maxelem 200000
iptables -I INPUT -p tcp -m multiport --dports 80,443 \
  -m set --match-set cc_block src -j DROP

# 查看当前有多少条、剩余多久
ipset list cc_block | tail -5
  • 另外,封 IP 之前先确认拿到的是真实客户端 IP。站点在 CDN 后面却没配回源段,封掉的可能就是 CDN 节点,一次操作全站不可用。

Q:反爬规则要不要对外说清楚?

  • 要做,但分层次。robots.txt 不是拦截手段,它是给愿意遵守的一方看的意图声明,该写清楚哪些路径不该抓。
  • 用户协议与隐私政策里写明「会做访问频率限制与安全审计」,比事后解释有说服力得多。
  • 但具体阈值不要公开。把「单 IP 每秒 5 次、burst 20」写进公开文档,等于给绕过者一份说明书。公开类别,不公开参数。

Q:拦截记录能随便对外披露吗?

  • 不能。封禁 IP 列表、完整 UA、访问路径,一旦贴到技术博客或群里,很可能连带暴露客户数据与内部接口。
  • 对外只披露聚合结论:攻击类型、量级、时间窗、处置结果,不带可定位到个人的明细。
  • 内部留存要有访问控制与操作审计。谁导出过日志、导出了多少,应该查得到。

Q:只做技术不管合规,会有什么实际后果?

  • 三条现实成本:客户投诉与退单(B 端最直接)、监管约谈与整改(尤其是日志里留了不该留的信息)、合作方直接换供应商(被误封一次就够)。
  • 反过来,把申诉通道和留痕做扎实,本身就是防护方案的说服力:客户会问「你们封错了怎么办」,答案具体比参数漂亮更有用。

Q:还有什么补充建议?

  • 把反爬做成可解释、可回滚、有申诉的三件套。可解释是每条规则都能说出为什么命中,可回滚是规则独立成文件能一键关掉,有申诉是误伤有出口。
  • 上线节奏建议:先观察 7 天只打标记不拒绝,再挑单一类规则真拒绝 2 至 3 天,最后全量。避开大促与发版窗口。
  • 每月复盘一次误封率:被拒请求里有多少来自真实用户(可从申诉量、下单失败量反推)。这个数字比拦截量更能说明防护质量。