不少站长都遇到过这种情况:白天风平浪静,一到凌晨网站就变慢甚至打不开。这不是巧合,而是 CC攻击 在挑时段。本文用 9 个问答讲清攻击为什么偏爱低谷时段、怎么用分时段防护策略把资源花在刀刃上、Nginx 限流阈值怎么按时间段切换、云防护等级怎么定时降档升档,以及怎样避免误伤夜间真实访客。
Q:CC攻击为什么偏爱凌晨和非业务高峰?
攻击者算的是「单位流量的破坏效率」,低谷时段的效率最高:
- 无人值守窗口:这个点运维在睡觉,告警响了也没人第一时间处置,攻击存活时间最长。
- 放大效果最好:低谷基线低,中等流量就能把服务压垮;同样规模放到白天高峰,可能连水花都看不到。
- 弹药更充足:攻击者手里的肉鸡大量是家用宽带和移动设备,这些设备夜里在线率最高。
- 先试探后总攻:很多攻击会先用低谷时段试探你的防护强度和响应速度,摸清之后再挑高峰动手。
所以「半夜被打」不是运气问题,而是攻击者的成本选择。
Q:分时段防护的核心思路是什么?
核心是阈值不该全年恒定。低谷基线很低,用高峰的宽松阈值等于不设防;反过来,高峰基线本来就高,套用低谷的严格阈值必然误伤真实用户。
- 高峰时段重可用性:阈值放宽,优先保证正常用户能下单、能付款。
- 低谷时段重拦截强度:阈值收紧,宁可多拦一点,因为夜里业务量小、误伤面也小。
- 告警响应也要分时段:白天工作群通知即可,夜间必须走电话升级,否则告警等于没发。
但有一个前提:你的业务在夜里是否真有真实流量。游戏、直播、外贸站和面向海外的站点,夜间可能才是高峰,直接套用「夜间严格」会误伤。
Q:怎么确定自己业务的高峰和低谷时段?
不要凭感觉,用访问日志按小时统计 14 天,取平均值看曲线:
# 按小时统计请求量(含 14 天数据时效果最好)
awk '{print substr($4,14,2)}' access.log | sort | uniq -c | sort -k2
# 按"日期 + 小时"双维度分桶,方便区分工作日与周末
awk '{print substr($4,2,11), substr($4,14,2)}' access.log | uniq -c | head -40
统计出来后划三档:请求量 > 日均 1.2 倍为高峰,0.5 到 1.2 倍为平峰,低于 0.5 倍为低谷。再单独拉一份节假日曲线——很多业务周末的峰谷结构和工作日完全不同。
Q:Nginx 怎么按时段切换限流阈值?
Nginx 的 limit_req 速率不能在运行时按变量切换,最实用的做法是定义两档 zone,用 include 文件加定时任务切换:
# http 块:定义两档速率(高峰宽松 / 低谷严格)
limit_req_zone $binary_remote_addr zone=cc_peak:10m rate=20r/s;
limit_req_zone $binary_remote_addr zone=cc_off:10m rate=5r/s;
limit_req_status 429;
# server 块:引用一个可被定时任务改写的片段
include /etc/nginx/cc-active.conf;
cc-active.conf 内容只有一行,随时可切换:
limit_req zone=cc_peak burst=40 nodelay;
定时切换:
# 08:00 切回高峰宽松档
0 8 * * * echo 'limit_req zone=cc_peak burst=40 nodelay;' > /etc/nginx/cc-active.conf && nginx -t && nginx -s reload
# 23:00 切到低谷严格档
0 23 * * * echo 'limit_req zone=cc_off burst=10 nodelay;' > /etc/nginx/cc-active.conf && nginx -t && nginx -s reload
三个关键点:一是必须先 nginx -t 再 reload,配置写错会直接重载失败;二是 burst 要跟着一起收紧,只降 rate 不降 burst,严格档会被突发额度吃掉;三是静态资源单独放行,别让图片和 CSS 跟着一起被限速。
Q:云防护/WAF 的防护等级能定时切换吗?
多数云 WAF 和高防都开放了 API,可以按时间切换策略组或调整阈值参数:
# 低谷时段切到严格策略组(示例接口,按服务商文档替换)
curl -s -X POST "https://api.example-waf.com/v1/policy/switch" \
-H "Authorization: Bearer $TOKEN" \
-d '{"domain":"www.example.com","policy_id":"strict-night"}'
两条经验:优先只调「阈值参数」而不是整体替换策略组,整体替换一旦接口返回异常,策略会停在一个谁都不认识的档位;切换动作要幂等并带失败告警,脚本跑挂了得有人知道。
Q:半夜没人值守,怎么让告警真正生效?
告警失效通常是两个原因:只是响了一下没人管,或者告警内容没法直接行动。
- 三级升级:企业微信/钉钉 → 电话 → 值班手机,夜间直接跳过第一级。
- 告警带动作:不要只说「流量上涨」,要给出「已在 XX 分钟内超过阈值,建议执行 XX 脚本升档」。
- 双条件触发:绝对量(超过 XX Mbps)与相对量(超过基线 1.5 倍)同时满足才告警,能滤掉大量误报。
- 自动处置兜底:有条件时让脚本自动升档防护等级,设好上限,等天亮再人工复盘。
- 抑制窗口:同一事件 10 分钟内不重复轰炸,避免告警风暴让人麻木。
Q:夜间严格策略会不会误伤真实用户?
会有风险,三类夜间真实流量必须先识别出来:海外访客(时差导致),夜班行业流量(游戏、直播、客服系统),合法自动化调用(合作方 API、数据同步任务)。
- 白名单级放行:海外 CDN 回源段、合作方 API 地址、内部探针与健康检查,全部加进免限名单。
- 按路径分级:登录、下单、支付接口走严格档;首页、列表页、静态资源保持宽松。
- 先降速再封禁:优先返回 429 而不是 403,真实用户可以慢一点,但不会直接被挡在门外。
- 先观察再拦截:新策略上线前先只记录不拦截,跑 3 到 7 天看会命中哪些正常请求。
Q:自动化切换怎么落地并保证可回滚?
把切换逻辑写成一个带回滚的脚本,任何一步失败都自动退回原配置:
#!/bin/bash
set -euo pipefail
CONF=/etc/nginx/cc-active.conf
BACKUP=$(mktemp)
cp "$CONF" "$BACKUP"
trap 'cp "$BACKUP" "$CONF"; nginx -s reload' ERR
printf 'limit_req zone=%s burst=%s nodelay;\n' "$1" "$2" > "$CONF"
nginx -t && nginx -s reload
logger -t cc-switch "switched to $1 burst=$2"
每次切换都写系统日志,事后才能把攻击时间线和策略变更时间线对齐——很多「越防越卡」的案例,就是切换时机选错了。
Q:还有什么补充建议?
- 先攒够基线再上策略:没有 14 天的小时级数据,分时段就是盲调。
- 分时段不替代入口防护:它只是把资源分配得更合理,真正的洪水还得靠 CDN 和高防挡在外面。
- 切换时间别固定成整点规律:攻击者会盯你的切换空档,可以随机偏移 10 分钟以内。
- 严格档不等于关闭:低谷收紧是为了提高拦截强度,不是把阈值调到正常用户都过不去。
- 把攻击时段分布纳入复盘:连续多日同一时段被打,说明攻击者在试探你的值守规律,这时候值班安排本身也是防护的一部分。
一句话总结:攻击看时段,防护也要看时段;高峰保可用性、低谷保拦截强度,再用白名单和降速兜住真实用户,这套分时段策略才算配得对。