大促前CC防护怎么准备?白名单报备与阈值协同

大促当天流量翻十倍,防护阈值和白名单要是没提前动,结果不是误封真实用户,就是放跑混在洪峰里的攻击。本文用 10 个问答讲清大促前的准备时间表、报备要写什么、阈值怎么算、压测流量怎么放行与回收。

Q:为什么大促期间 CC 防护最容易出事?

  • 因为两个方向的错误会同时发生,而且互相掩护。
  • 一边是阈值按平峰配的:日常 50 QPS 就限流,活动一来正常用户先被 429,客服电话当天就炸。
  • 另一边是为了不误封把规则调到形同虚设:攻击正好混在洪峰里,你分不清哪个是抢购的真人、哪个是刷接口的脚本,等于给攻击者开了窗口。
  • 根子在于大促流量的特征和 CC 攻击高度重叠:短时高并发、路径高度集中、大量新 IP。这三点既是活动特征,也是攻击特征。
  • 所以核心不是”把阈值调大”,而是分层:最贵的接口单独隔离限流,可缓存的页面全推到边缘,让洪峰到不了源站。

Q:提前多久开始准备?时间表怎么排?

  • 按 T-14 倒排,每个节点只做一件事,别堆到前一天:
  • T-14 压测:压出活动页面的真实 QPS 上限。取 CPU 打到 70% 时的 QPS,不要压到报错为止,那个数没有余量。
  • T-7 报备:把活动时间、预估峰值、主要入口路径、源站变更,正式提交给 CDN/WAF/高防供应商,拿到工单号。
  • T-3 配置:阈值、白名单、缓存规则改完并灰度上线。静态资源预热,别等开抢才回源。
  • T-1 冻结:停止结构性变更,只保留回滚能力。值班表和升级路径确认到人。
  • 当天:只调参数,不改结构。改配置结构是事故高发动作。
  • T+1 回收:临时策略按顺序撤,别留着过年。

Q:向防护供应商报备,具体要写清哪些内容?

  • 报备不是打个招呼,是让对方的值班同学能在凌晨三点看懂你要什么。七项缺一不可:
  • 活动起止时间:精确到分钟,标明时区。跨零点的活动最容易出问题。
  • 预估峰值:QPS、带宽(Mbps)、独立 IP 数,给区间不给单点。
  • 主要入口路径:列表页、详情页、下单接口、秒杀接口,逐条列出。这是对方配规则的基础。
  • 源站可承受上限:超过之后希望怎么处理,是限速、排队还是返回活动结束页。你给指令,对方照做。
  • 紧急联系人:手机号,不要只留工单系统。工单在攻击中是慢的。
  • 白名单 IP 段:压测机、拨测节点、办公出口,逐条注明用途和到期时间。
  • 临时放宽项:写明规则 ID、放宽幅度、到期时间。只写”放宽 CC 防护”是最容易被拒的表述。

Q:阈值到底怎么上调?有没有可用的算法?

  • 有,用两段式计算,两头都要卡住:
  • 日常阈值 = 压测 QPS 上限 × 0.7,留 30% 余量给突发。
  • 活动阈值 = 活动预估峰值 × 1.3,但不得超过源站上限 × 0.85。前者防误封,后者防打穿。
  • 最容易犯的错是只调边缘不调源站:CDN 放过来了,源站自己的 limit_req 还是平峰配置,结果边缘显示 200,用户那边 503。
  • 边缘和源站要同时动,并且源站桶要比边缘松一档,让边缘先拦,源站兜底。
# 活动接口单独开桶,与全站限流隔离
limit_req_zone  $binary_remote_addr zone=act_api:20m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=act_conn:10m;

location = /api/seckill {
    limit_req  zone=act_api burst=60 nodelay;
    limit_conn act_conn 20;
    limit_req_status 429;
    limit_conn_status 429;
    proxy_read_timeout 10s;   # 活动接口不要长等,快速失败比拖死好
}

location / {
    limit_req zone=global_api burst=20 nodelay;
}

Q:压测流量怎么放行,又不留后门?

  • 核心原则:白名单只放”人”,不放”路径”。全站对一个 IP 段放行,等于把限流关掉一半。
  • 三个条件同时满足才认:专属 UA + 自定义头签名(HMAC + 时间戳,5 分钟过期)+ 来源 IP 段。
  • 规则要带到期日,文件命名就用日期,再用 cron 自动清理。靠人记着删的白名单,最后都会变成永久后门。
# 压测放行:UA + 签名头双条件
map "$http_user_agent|$http_x_loadtest_sig" $is_loadtest {
    default                          0;
    "~*LoadTestBot/1\.0\|[a-f0-9]{32}"  1;
}

map $is_loadtest $limit_key {
    0  $binary_remote_addr;
    1  "";
}

server {
    # limit_key 为空时不进桶,即豁免限流
    limit_req  zone=global_api burst=20 nodelay;
    limit_conn act_conn 20;
}

# 每日 03:00 清理过期白名单并校验配置
0 3 * * * find /etc/nginx/conf.d/whitelist -name '*.conf' -mtime +7 -delete \
          && nginx -t && nginx -s reload
  • 压测结束后当天就撤,不要等”活动结束一起清”。压测机半年后可能已经换主人了。

Q:活动页面怎么配才抗得住洪峰?

  • 思路一句话:让能缓存的都不回源,让必须回源的都便宜。
  • 列表页、详情页做整页缓存(CDN 边缘 + nginx 本地两级),TTL 短一点没关系,关键是命中率要顶住。
  • 价格和库存这类动态数据用接口单独拉,走片段缓存或短 TTL,不要因为一个库存数字让整页不缓存。
  • 下单和秒杀接口不能缓存,只能”限流 + 排队 + 令牌”,并且要能快速失败,别让它拖住连接。
  • 静态资源独立 location,绕开 PHP,顺手把日志关掉,减少 IO。
location ~* \.(js|css|jpg|jpeg|png|webp|woff2|svg)$ {
    expires 7d;
    add_header Cache-Control "public, immutable";
    access_log off;
    open_file_cache max=10000 inactive=60s;
}

Q:临时白名单会不会变成绕过口子?

  • 会,而且这是活动期最常见的安全债。判断标准很简单:这条规则有没有到期时间、有没有责任人。
  • 每条临时豁免必须绑三样:IP + 路径 + 时间窗。只写 IP 的豁免,在攻击者拿到这个 IP(比如复用的云主机、被入侵的办公出口)时就是一条后门。
  • 统一放在单独目录、单独 include,活动结束直接删目录再 reload,比在几十条规则里找要可靠得多。
  • 常见情况:去年活动加的白名单没人撤,今年还在生效,而那个 IP 早换了用途。定期 grep 一遍 allow 和 map,比出事后再查快。

Q:活动期间盯哪几个数?看板怎么摆?

  • 业务指标放最上面,技术指标放下面。老板只看前四个,运维看后四个:
  • 下单成功率、支付转化率:真指标,掉了就是真出事,不用解释。
  • 429/403 比例:超过 1% 说明阈值偏紧,正在误封真人;低于 0.05% 且攻击特征明显,说明阈值太松。
  • P95 + 源站 CPU:先看 CPU 再看 QPS。QPS 涨 CPU 没涨说明缓存生效;CPU 先满说明缓存穿了。
  • 缓存命中率:掉 10 个百分点就要查回源,洪峰期缓存击穿比攻击更致命。
  • 单 IP 请求分布 Top10:活动期正常用户的分布是长尾的,如果 Top10 突然变得很均匀、量都很大,那就是攻击。

Q:真攻击和真洪峰同时来,怎么分、怎么处置?

  • 分三条看,五分钟内能定性:
  • 路径分布:洪峰符合活动设计(列表页 → 详情页 → 下单),攻击只打最贵的那一个接口,前后不连贯。
  • 资源加载:真人会拉 js/css/图片,Referer 正常;脚本通常只请求接口,静态资源占比极低,Referer 为空。
  • 转化数据:洪峰的转化率落在预期区间,攻击的请求转化率为 0,而且下单参数高度雷同。
  • 处置原则一条:先保下单链路。其余接口(评论、推荐、搜索)一律降级到静态页,把资源让给主链路。
  • 别在这个时候做大范围封 IP。洪峰期的误封代价是真实的GMV,宁可限速也不要硬封。

Q:活动结束后怎么收尾?

  • 按”从内到外”回收,每步间隔 24 小时,边收边看指标:
  • 第一步撤压测白名单和临时豁免,这两类最危险,先撤。
  • 第二步把活动接口的独立桶降档回日常值,观察 429 比例有没有异常上升。
  • 第三步把边缘的 CC 阈值降回基线,同时确认源站桶也一起降。
  • 最后出一页复盘,只写四个数:峰值 QPS、拦截量、误封量、最大处置耗时。下次活动直接拿这页当输入。
  • 活动期日志保留 30 天。真要追刷单、追恶意竞争,证据全在这段时间的日志里。