在抗 CC(Challenge Collapsar)攻击的实战中,只靠后端限流或只靠前端的 JS 弹窗验证都远远不够------前者容易被模拟浏览器的僵尸网络绕过且易拖垮业务,后者面对大规模随机 IP 攻击时会造成前端挑战泛滥、用户体验崩坏。
真正有效的做法,是构建由外向内、逐层过滤的多层级 CC 防护体系 ,让前端验证负责"筛掉低级 bot",后端限流负责"兜底异常流量",两者通过阈值梯度和挑战升级策略形成协同闭环。
一、多层级 CC 防护总体架构
推荐按以下五个层次部署(外 → 内):
[用户浏览器]
↓
[L1 CDN/边缘节点] → IP 粗粒度限流 + Geo 封禁 + 简单 JS Challenge
↓
[L2 WAF / 接入网关] → 前端验证(JS 计算/ Cookie Challenge / CAPTCHA)+ 精细化限流
↓
[L3 应用层/API Gateway] → 接口级令牌桶 / 滑动窗口限流(per-IP / per-User / per-API)
↓
[L4 微服务/业务] → 线程池隔离、方法级限流(Sentinel / Hystrix)
↓
[L5 后端资源] → 熔断降级(DB 慢查询熔断、队列积压丢弃)
核心原则:
-
外层(L1/L2)尽可能用低成本方式拦掉自动化工具、扫描器、弱 bot;
-
内层(L3/L4)做精确的 QPS/并发控制,防止单用户或单接口把后端打死;
-
各层阈值由外到内递减,避免内层先于外层触发导致误杀或雪崩。
二、L1:CDN / 边缘节点 --- 第一道粗筛
大多数云 CDN(阿里云 DCDN、腾讯云 EO、Cloudflare 等)自带 CC 防护:
-
单 IP 每秒请求数限制(如 100 QPS/IP/5s),超出直接丢弃或弹出 JS Challenge。
-
全局 QPS 封顶 + 自动清洗,应对反射型泛洪。
-
UA / Geo / ASN 封锁:封禁常见 scanner UA、不通国家区域。
-
对搜索引擎 UA(Googlebot/Baiduspider)做正向 DNS 反查验证后加白。
✅ 此层不要求 100% 精准,目标是把 60%~80% 的垃圾流量消化在边缘,减轻回源压力。
三、L2:前端验证 + 网关限流(最关键协同层)
这是"前端验证与后端限流协同"的主战场。
1. 前端验证三种形态及适用场景
| 验证方式 | 原理 | 优缺点 | 适用场景 |
|---|---|---|---|
| **JS Challenge(运算挑战)** | 返回 307/200 含 JS,要求浏览器计算 hash 后携带 Cookie 重访 | 无感、拦脚本 bot;但高级 headless Chrome 可绕过 | 默认 CC 挑战,首次访问或触发轻度限流时 |
| **Cookie Challenge(静默种 Cookie)** | 302 跳转种 cookie,再次请求校验 | 极轻量;仅防无 cookie 的简单请求 | 配合 JS Challenge 做二级过滤 |
| CAPTCHA / 滑块验证 | 人机交互验证,通过后发放 token/session | 强人机区分;影响 UX,移动端需注意 | 持续异常 IP、多次 JS Challenge 失败后升级 |
协同逻辑:
正常用户 → 首次请求 → 触发 JS Challenge(无感)
→ 浏览器完成计算 → 带 Cookie 重新请求 → 放行
Bot / 脚本 → 不带 Cookie / 不执行 JS → 反复被 Challenge 或 403
异常 IP(高频)→ JS Challenge 多次仍不通过 → 升级为 CAPTCHA
仍异常 → L1 CDN 封 IP 一段时间
2. Nginx + Lua(OpenResty)实现 JS Challenge + 限流示例
下面给出一个思路级配置示例(生产需按情况调整):
http {
lua_shared_dict cc_zone 100m;
server {
listen 80;
server_name example.com;
# 基础 IP 限流:100r/s,突发 200
limit_req_zone $binary_remote_addr zone=cc_limit:100m rate=100r/s;
# JS Challenge 标记(记录已通过 Challenge 的 IP:Cookie)
lua_shared_dict js_done 50m;
location / {
# Step1: 检查是否已持有有效 cc_cookie
access_by_lua_block {
local cookie = ngx.var.http_cookie
if cookie and string.find(cookie, "cc_pass=1") then
return -- 已通过挑战,直接进入限流
end
-- Step2: 简易计数器,判断是否要弹 JS Challenge(避免每个请求都弹)
local key = "js:" .. ngx.var.binary_remote_addr
local dict = ngx.shared.cc_zone
local cnt, err = dict:incr(key, 1, 0, 60) -- 60s TTL
if cnt > 10 then -- 同一 IP 60s 内 >10 请求且未带 cookie → 弹挑战
ngx.header['Content-Type'] = 'text/html'
ngx.say([[
<html><body>
<script>
// 简单 JS 运算挑战
var t = Date.now();
while(Date.now() - t < 800); // 模拟计算耗时
document.cookie="cc_pass=1; path=/; max-age=900";
location.reload();
</script>
<p>Verifying browser...</p>
</body></html>
]])
ngx.exit(200)
end
}
# Step3: 通过挑战后,执行限流(防绕过)
limit_req zone=cc_limit burst=200 nodelay;
proxy_pass http://backend;
}
}
}
💡 要点 :只有带
cc_pass=1Cookie 的请求才进入limit_req,纯脚本直接拿不到 Cookie 就卡在 JS Challenge 层,不会消耗后端限流桶。
3. 云 WAF / 商业网关配置建议
-
开启**"浏览器检查(Browser Integrity Check)"** + "JS Challenge 自动下发"
-
设置触发条件:单 IP QPS > N 或 请求特定高频路径(如
/login、/search?q=*) -
配置挑战失败 N 次 → 自动封 IP M 分钟 或 弹出 CAPTCHA
-
将支付回调、微信/支付宝 Notify URL、内部服务 mTLS 调用加入白名单,跳过所有 Challenge
四、L3:应用层/API Gateway --- 精准限流兜底
即使前端验证拦掉了大部分 bot,必须假设前端可被绕过(高级 bot 可模拟 JS 执行),所以应用层要有独立限流:
-
算法选择 :推荐令牌桶(Token Bucket) 控制平均 QPS,**滑动窗口(Sliding Window)**更公平但稍重。
-
限流维度组合:
-
per IP(防单一出口攻击) -
per User/UID(登录态,防账号滥用) -
per API(热点接口如/api/search单独设低阈值)
-
-
示例 --- Nginx limit_req(应用层前置):
针对登录接口更严格
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/s;
location = /api/login {
limit_req zone=login_limit burst=10 nodelay;
proxy_pass http://app;
} -
Java 应用可用 Guava RateLimiter (单机)或 Sentinel(分布式、支持预热、冷启动、熔断)。
⚠️ 此处阈值应低于外层 WAF 允许通过的预期峰值,作为最后一道数学防线。例如 WAF 放行预计 ≤5000 QPS,应用层设 5500 QPS 熔断。
五、协同配置关键参数设计参考
| 层级 | 动作 | 典型阈值(参考) | 触发条件 |
|---|---|---|---|
| CDN 边缘 | IP 限流 + JS Challenge | 100~200 QPS/IP/60s | 全局或指定 URI |
| WAF 网关 | JS Challenge → CAPTCHA → 封 IP | Challenge 失败 ≥3 次/60s → CAPTCHA;≥5 次 → 封 15min | 请求无 Cookie / 高频 |
| 应用层 | Token Bucket 限流 | 登录 5 QPS/IP,普通 API 50 QPS/IP | 所有通过前层流量 |
| 微服务 | Sentinel 熔断 | RT > 500ms 连续 20 次 → 熔断 10s | 下游 DB/RPC 慢 |
六、常见坑 & 验收建议
避坑:
-
❌ 对所有接口(含回调/健康检查)开启 JS Challenge → 支付通知永远收不到
✅ 配置精确白名单路径
-
❌ 搜索引擎被 JS Challenge 拦 → SEO 归零
✅ 对 Googlebot/Baiduspider 做 IP 反向验证后加白
-
❌ 分布式多实例应用层限流用本地内存 → 限流效果被 N 倍放大
✅ 用 Redis 滑动窗口或 Sentinel 集群流控
-
❌ Challenge 页面无 noscript 提示 → 禁用 JS 的用户完全无法访问
✅ 返回 403 并提示"请启用 JavaScript 或联系客服"
验收:
-
用
ab / wrk模拟单 IP 高压请求 → 应见到 JS Challenge 返回,后端无增长。 -
模拟通过 Challenge 后继续压 → 应用层 limit_req 应开始 503/429。
-
用真实 Googlebot IP(验证正向解析)抓取 → 直接 200,无 Challenge。
-
大促前做全链路压测,观察各层拦截量占比(理想:CDN > WAF > App)。
一句话总结
**多层级 CC 防护 = 边缘粗筛(IP 限流/JS Challenge)+ WAF 前端验证(无感 Challenge → CAPTCHA 升级)+ 应用层精确限流兜底。**
前端验证把成本低的无脑 bot 挡在外面,后端限流保证即便挑战被绕过也不穿透业务------两层通过阈值梯度、挑战升级、白名单机制紧密协同,才能在抗 CC 同时保住真实用户体验。
如需,我也可以根据你用的具体组件(Nginx 原生 / OpenResty / Kong / APISIX / 云 WAF 控制台)给更贴近生产的完整配置片段。