很多站长被 CC 攻击后第一反应是「谁这么闲」,其实答案很直接:因为太便宜了。本文用 10 个问答讲清 CC 攻击的成本结构、代理池是怎么被批量租出去的,以及站长能从缓存、算力挑战、限速、封禁四个层面把攻击者的成本抬到多高,并附可直接复制的配置。
Q:CC 攻击一次到底要花多少钱?
公开讨论的价格区间大致是这样:按「并发数 + 时长」计费,几十元就能租到几百并发打一天;带代理池的「真人模拟」套餐按天算,通常在几十到几百元之间;如果租的是秒拨 IP 池,再叠加一层按 IP 计费的成本,但也远低于一台服务器的价格。
- 极低价区间(几十元级):固定一批 IP 或单一 IDC 段,靠暴力并发硬顶,特征明显,最容易被限速和封段。
- 中价区间(数百元级):混入代理池,IP 分散在不同 AS 和地区,UA 与 Referer 做得比较像浏览器。
- 较高价区间(千元级):秒拨 IP + 真实浏览器内核(无头浏览器集群),能执行 JS、能带 Cookie,这类才是真正难拦的。
也就是说,攻击者的成本主要由「IP 质量」决定,而不是「流量大小」。这一点决定了防守方的思路:能抬高攻击预算的动作,比单纯加带宽有用得多。
Q:为什么 CC 攻击的成本能压到这么低?
三块拼起来的结果。
- 僵尸网络与代理池的边际成本几乎为零。被感染的设备、被扫出来的开放代理、被误配置的公共代理节点,本身不产生额外费用,谁手上有池子,谁就能反复出租同一批资源。
- 不需要带宽,只需要请求数。CC 打的是应用层,一个 HTTP 请求只有几百字节,一万个并发每秒也占不了多少带宽,但足以让一台未做缓存的动态站点的 PHP 进程全部占满。
- 攻击的门槛被工具化了。攻击平台把 IP 池、UA 轮换、请求节奏、验证码识别打包成「填个 URL 就能下单」的服务,使用者不需要任何技术背景。
换个角度看:攻击者只需要成本低于收益就愿意动手。防守方的目标不是「绝对拦死」,而是让攻击成本超过攻击者愿意支付的价格——这是所有成本抬升动作的底层逻辑。
Q:什么叫「抬升攻击成本」?该定什么目标?
同一个攻击者,在手上有 N 个 IP 的情况下,能打出的有效请求数大致等于「IP 数 × 单 IP 有效请求率」。所以抬升成本只有两个抓手:
- 降低单 IP 的有效请求率——让他手里的 IP 更快被打标记、更快被限速、更快被验证码消耗。
- 提高获得高质量 IP 的门槛——让原来「够用」的低质量 IP 池失效,迫使他升级到更贵的秒拨或浏览器集群。
目标可以量化:把攻击者从「几十元档」逼到「千元档」,或者让同等预算下能打出的有效请求下降一个数量级。这比追求「一个请求都不进来」现实,也不会因为误封伤到正常用户。
Q:第一层,怎么让攻击流量根本不产生计算成本?
最省钱的一层:让请求被缓存命中,不落到后端。攻击者对静态资源的请求,命中缓存就等于零成本;真正贵的是每次都要跑 PHP/数据库的动态请求。
# /etc/nginx/conf.d/cache.conf
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=pagecache:200m
max_size=10g inactive=30m use_temp_path=off;
# 只缓存 GET/HEAD,带登录态和后台的请求一律绕过
map $request_method $cache_method_ok {
default 0;
GET 1;
HEAD 1;
}
# 忽略无关的营销参数,把随机参数请求收束到同一份缓存
map $args $cache_ok_args {
default "";
"~(?:^|&)id=([0-9]+)" "&id=$1";
"~(?:^|&)page=([0-9]+)" "&page=$1";
}
# 服务端缓存策略,命中率是关键指标
location / {
proxy_cache pagecache;
proxy_cache_key "$scheme$host$uri$cache_ok_args";
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_lock on;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
proxy_cache_bypass $cookie_wp_logged_in $arg_nocache;
add_header X-Cache-Status $upstream_cache_status always;
proxy_pass http://backend;
}
验证方式很简单:压测前看命中率,压测中盯 X-Cache-Status。命中率从 30% 提到 90%,等于把攻击者每一次有效请求的单位成本抬了 3 倍——他必须发更多请求才能达到同样效果。
Q:第二层,JS 挑战和验证码为什么能显著抬高成本?
因为它们把「发一个 HTTP 请求」变成了「执行一段计算并保持状态」。这一步对正常用户几乎无感,对脚本却是数量级的成本差。
- JS 挑战(无感验证):要求客户端在短时间内算出一个哈希并回发。用 curl 或简单脚本的请求会直接失败,只有真实浏览器或无头浏览器才能通过。
- 验证码:通过打码平台识别一次的成本是几厘到几分,看着不多,但一旦并发到了每秒几千次,每秒的打码费用就是几十元,预算会以肉眼可见的速度烧掉。
- 下发策略比手段本身更重要:不要全站开启,只对「高成本路径 + 命中可疑特征」的请求下发。全站开启既伤 SEO 也伤真实用户体验。
实操上建议这样分级:正常流量放行 → 单 IP 频率异常降速 → 仍持续异常下发无感 JS 挑战 → 再持续异常才上交互式验证码 → 最后才封禁。让攻击者每一级都得付出额外成本,而正常用户几乎感知不到。
Q:第三层,Nginx 限速该怎么配才能「限得住又不误伤」?
关键是按「是否动态」分开限速,而不是全站一个阈值。静态资源阈值可以很宽松,动态接口必须收紧。
# 定义两个限速区:普通页面与高风险接口
limit_req_zone $binary_remote_addr zone=page_req:20m rate=5r/s;
limit_req_zone $binary_remote_addr zone=api_req:20m rate=2r/s;
limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
limit_req_status 429;
limit_conn_status 429;
server {
location / {
limit_req zone=page_req burst=20 nodelay;
limit_conn perip_conn 30;
}
# 搜索、登录、下单等高成本路径单独收紧
location ~* ^/(search|login|cart|api)/ {
limit_req zone=api_req burst=5 nodelay;
limit_conn perip_conn 10;
}
}
几个必须强调的参数:rate 是稳态速率,burst 是允许的瞬时突发,nodelay 表示突发部分不排队直接返回 429。不加 nodelay 会让请求排队,攻击场景下反而容易把连接卡满。429 一定要配自定义错误页,避免攻击者一眼看出是限速拦下的。
Q:怎么让攻击者手里的 IP 快速失效?
封禁的价值不在「封掉几个 IP」,而在迫使攻击者不断换资源。他换得越快,成本越高。
# 用 ipset 做海量封禁,比一条条 iptables 规则快得多
ipset create ccban hash:net timeout 1800 -exist
ipset add ccban 198.51.100.0/24 -exist
iptables -I INPUT -m set --match-set ccban src -j DROP
# 自动封禁脚本思路:单位时间内的 429/502 次数超阈值即入池
# 日志侧筛选出高频来源 IP 并批量加入
awk '{print $1}' /var/log/nginx/access.log \
| sort | uniq -c | sort -rn | head -100 > /tmp/topip.txt
同类思路还能用在另外两个维度上:UA 维度(把空 UA、可疑 UA 的请求统一限速,注意用空 key 技巧避免误伤正常 UA)和 JA3/TLS 指纹维度(同一指纹后面拖着成百上千个 IP,这类请求基本可以判定为脚本流量,用指纹封比用 IP 封效率高得多)。
这里有个经验判断:当你发现封禁列表里 IP 换得越来越快、C 段越来越杂、地区跨度越来越大,说明攻击成本已经被抬上去了——他正在被迫消耗更贵的资源。
Q:有没有必要做「慢速」防御?比如给攻击者拖时间?
有必要,但要用在对的位置。对正常请求不要拖慢,只对已经命中可疑特征的连接做延迟响应。
- 可疑请求延迟 1 到 3 秒:攻击者的并发是有限资源,连接被占住就意味着他必须开更多并发才能维持同样的攻击强度。
- 连接耗尽型攻击要反向处理:如果是 Slowloris 这类慢连接攻击(占住连接不发完整请求),策略完全不同——要收紧
client_header_timeout、client_body_timeout并限制单 IP 连接数,而不是拉长响应。 - 不要把延迟用在正常用户路径上:任何给正常用户增加 1 秒的配置,都是在用自己的转化率补贴防护。
Q:怎么量化「攻击成本抬升」的效果?
看四个指标就够了,全部能从 Nginx 日志和 CDN/WAF 后台拿到。
- 攻击来源 IP 更换频率:同一攻击持续期间,Top 100 攻击 IP 的重合度。重合度持续下降 = 攻击者被迫不断换资源。
- 单 IP 平均请求数:越封越低说明单 IP 存活时间被压缩。
- 429 / 挑战下发占比:反映有多少请求被挡在了计算之前。
- 回源请求数与 CPU 负载:这是最直观的「攻击是否影响业务」的判断依据,也是成本抬升最终要保护的东西。
如果攻击时长从「持续 5 小时」变成「打 20 分钟就停」,通常说明对方觉得不划算了——这比任何单点拦截率都更能说明防护有效。
Q:还有什么补充建议?
按顺序落地一遍:① 静态与动态分层缓存,把命中率做到 80% 以上 → ② 高风险路径单独限速,静态资源放宽 → ③ 按 IP、UA、指纹三个维度做分级拦截 → ④ 可疑流量依次下发降速、JS 挑战、验证码 → ⑤ 上线自动封禁并设置自动解封时长 → ⑥ 监控来源 IP 更换频率与单 IP 请求数变化。
补三个容易踩的坑。第一,不要全站开验证码:搜索引擎抓取、支付回调、监控探活都会被一起拦掉,损失比攻击本身大。第二,封禁一定要设有效期:秒拨 IP 池会回收再分配,长期黑名单迟早会误伤真实用户,用 ipset timeout 自动过期最省事。第三,别把 CDN/WAF 当成唯一防线:源站 IP 一旦泄露直连,前面所有成本抬升动作都会失效,源站必须只允许回源 IP 访问。
一句话总结:CC 防护的本质是成本博弈——你无法让攻击消失,但可以让它变贵。缓存命中率、挑战下发、分级限速、快速封禁这四件事做到位,攻击者的预算很快就不够用了。