多层级 CC 防护体系:前端验证与后端限流的协同配置实践

在抗 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 或联系客服"

验收:

  1. ab / wrk模拟单 IP 高压请求 → 应见到 JS Challenge 返回,后端无增长。

  2. 模拟通过 Challenge 后继续压 → 应用层 limit_req 应开始 503/429。

  3. 用真实 Googlebot IP(验证正向解析)抓取 → 直接 200,无 Challenge。

  4. 大促前做全链路压测,观察各层拦截量占比(理想:CDN > WAF > App)。


一句话总结

**多层级 CC 防护 = 边缘粗筛(IP 限流/JS Challenge)+ WAF 前端验证(无感 Challenge → CAPTCHA 升级)+ 应用层精确限流兜底。**​

前端验证把成本低的无脑 bot 挡在外面,后端限流保证即便挑战被绕过也不穿透业务------两层通过阈值梯度、挑战升级、白名单机制紧密协同,才能在抗 CC 同时保住真实用户体验。

如需,我也可以根据你用的具体组件(Nginx 原生 / OpenResty / Kong / APISIX / 云 WAF 控制台)给更贴近生产的完整配置片段。

相关推荐
秋91 小时前
Windows 环境下 Redis 部署详解:从选型、安装到生产级配置与运维
运维·windows·redis
ZC跨境爬虫1 小时前
跟着MDN学HTML_day_47:(Document接口)
前端·javascript·ui·html·ecmascript·音视频
一起逃去看海吧1 小时前
Dify-01-docker安装 和 dify部署
运维·docker·容器
林瞅瞅1 小时前
Jenkins+Docker实现Nuxt2自动化部署
服务器·ci/cd
学习论之费曼学习法1 小时前
ReAct框架深度解析:让Agent会思考再行动
前端·react.js·前端框架
前端 贾公子1 小时前
从零开始:使用Node.js和Cheerio进行轻量级网页数据提取
前端·vue.js
星恒讯工业路由器1 小时前
企业组网 企业加密内网、内网穿透、专线组网,三种方式该怎么选
网络·物联网·智能路由器·信息与通信
H Journey1 小时前
Linux查看进程命令
linux·运维·进程