CC攻击(Challenge Collapser)的本质不是单纯拼带宽,而是通过大量看似正常的请求消耗服务器资源,让真实用户无法访问。攻击者往往利用代理IP池,每个IP只发送少量请求,传统的IP频率限制很难精准拦截。更棘手的是,这类请求通常针对动态页面、搜索接口、短信发送、登录注册等消耗CPU和数据库连接的URL,单次请求就可能触发多次后端查询。因此处理高并发恶意请求的核心思路,不是简单地“封IP”,而是要在请求进入业务逻辑之前,用低成本的方式识别并阻断自动化流量。
首先要做的是拆分流量入口。把静态资源和动态请求彻底分离,静态文件走CDN或Nginx直接返回,动态请求才进入应用层。很多CC攻击会混合请求静态页面和动态接口,如果静态资源也回源到后端,攻击成本会成倍增加。通过配置Nginx的location规则,对jpg、png、css、js等文件设置长缓存和独立限速,后端只处理必须动态生成的请求。这一步看似基础,但在真实攻击中能直接减少60%以上的无效回源压力。
接下来要在Nginx层建立多维度限频体系。单纯基于IP的限制容易误伤企业出口或学校共享IP,所以需要结合IP、UA、Cookie、请求路径多个维度做组合判断。比如同一个IP对同一URL在1秒内超过20次请求,直接返回444;如果某个IP在10秒内请求了超过5个不同的动态URL,且UA为空或为常见攻击工具特征,则拉入黑名单。Nginx的limit_req模块可以基于内存做高效的令牌桶限流,配合map指令还能实现动态黑白名单。
http {
limit_req_zone $binary_remote_addr zone=perip:20m rate=10r/s;
limit_req_zone $binary_remote_addr$uri zone=perurl:20m rate=30r/s;
map $http_user_agent $is_bad_ua {
default 0;
"" 1;
~*curl 1;
~*wget 1;
~*python 1;
~*java 1;
}
server {
if ($is_bad_ua) {
return 444;
}
location /api/ {
limit_req zone=perip burst=20 nodelay;
limit_req zone=perurl burst=30 nodelay;
proxy_pass http://backend;
}
}
}
上面的配置中,perip限制单IP每秒10个请求,perurl限制单IP对同一URL每秒30个请求,burst允许短时突发但不会无限排队。UA黑名单直接拦截常见命令行工具和脚本语言特征,虽然攻击者可以伪造UA,但能过滤掉大量低水平扫描和测试流量。需要注意的是,limit_req返回的是503状态码,攻击者看到503会认为攻击生效,所以更推荐用return 444直接断开连接,不返回任何内容。
针对代理IP池攻击,IP频率限制的效果会大打折扣。攻击者可能动用数千甚至数万个IP,每个IP每分钟只发几个请求,完全在正常阈值之内。这时候需要引入行为分析。正常用户访问网站通常有明确的路径依赖:先访问首页,再浏览列表,最后进入详情页,两次请求之间有时间间隔。而CC攻击的请求往往是直接命中目标URL,缺少前置页面访问,且请求间隔极短或完全随机。可以在Nginx层用Lua脚本记录每个IP的访问序列,检查是否在访问动态接口前有过正常的页面浏览行为。如果没有,则要求先通过JavaScript跳转验证。
JavaScript跳转验证是性价比极高的CC防护手段。原理是当请求到达时,不直接返回真实内容,而是返回一个包含JavaScript代码的页面,这段代码会计算一个特定的Cookie值并重新请求。正常浏览器会自动执行JS并带上Cookie,而大多数攻击脚本不会解析执行JavaScript,因此无法通过验证。这个方案可以在Nginx层用Lua实现,也可以接入现成的WAF模块。关键是验证逻辑要足够轻量,不能引入额外的后端压力。
location /verify {
content_by_lua_block {
local token = ngx.md5(ngx.var.remote_addr .. ngx.var.http_user_agent .. ngx.var.time_local)
ngx.header["Set-Cookie"] = "cc_token=" .. token .. "; path=/; max-age=3600"
ngx.say([[]])
}
}
更进一步的方案是使用无Cookie的验证方式,比如要求客户端计算一个简单的数学题或执行一段哈希运算,将结果作为参数重新请求。这种方式对浏览器的兼容性更好,也能防御那些虽然支持Cookie但不执行JS的自动化工具。但要注意,验证逻辑不能过于复杂,否则会影响真实用户的访问体验,尤其是移动端弱网环境。
当攻击流量已经到达应用层,后端服务的保护就变得至关重要。数据库连接池是CC攻击最常见的瓶颈,攻击者可能针对搜索接口或列表页发起大量请求,每个请求都触发复杂的SQL查询。此时需要在应用层增加缓存层,把热点数据的查询结果缓存到Redis或Memcached中,设置合理的过期时间。对于搜索类接口,可以限制单IP的搜索频率,并对搜索结果做分页缓存。如果攻击者绕过前端限频直接请求后端,应用层还需要有独立的限流组件,比如Guava RateLimiter或Sentinel,对核心接口做兜底保护。
对于登录、注册、短信发送这类高消耗接口,CC攻击的危害更大,不仅消耗服务器资源,还可能触发短信费用或账号安全风险。这类接口必须单独设置严格的限频策略,比如同一IP每分钟最多3次,同一手机号每小时最多5次,同一设备指纹每天最多10次。同时引入验证码机制,在请求频率达到阈值后强制要求图形验证码或滑块验证。验证码本身也会消耗资源,所以不能对所有请求都启用,而是作为限频触发后的升级策略。
还有一个容易被忽视的点是HTTP协议层面的优化。CC攻击的请求往往带有不完整的请求头、异常的Content-Length、缓慢的请求体发送等特征。通过调整Nginx的client_header_timeout、client_body_timeout、keepalive_timeout等参数,可以快速释放被慢速攻击占用的连接。对于HTTP/1.0的请求,限制单个连接的最大请求数;对于HTTP/2,可以设置并发流的上限。这些参数调整虽然不能完全阻止CC攻击,但能显著提高服务器在攻击状态下的连接处理效率。
日志分析在CC防护中扮演着重要角色。攻击发生时,通过分析Nginx访问日志,可以快速定位攻击目标URL、攻击来源IP段、请求特征等信息。建议开启Nginx的日志采样,在正常状态下记录所有请求,在攻击状态下只记录被拦截的请求,避免日志写入成为新的瓶颈。同时可以用脚本定期分析日志,统计每个IP的请求分布,自动将异常IP加入防火墙黑名单。这个过程可以做成定时任务,每5分钟执行一次,实现准实时的自动封禁。
对于大规模CC攻击,单台服务器的防护能力始终有限,这时候需要考虑分布式防护架构。在多个节点部署相同的防护策略,通过DNS轮询或负载均衡分散流量。如果攻击流量超过单个机房的带宽,可以接入专业的DDoS/CC防护服务,利用其海量带宽和清洗能力过滤攻击流量。但要注意,第三方防护服务通常只能清洗网络层的攻击,对于应用层的CC攻击,仍然需要自己在源站做好行为分析和限频策略。
最后要强调的是,CC防护不是一次性配置就能一劳永逸的。攻击者会不断变换手法,防护策略也需要持续迭代。建议建立一套完整的监控告警体系,实时关注QPS、响应时间、错误率、连接数等核心指标,当指标异常时自动触发应急响应。同时定期进行压力测试和攻防演练,验证防护策略的有效性。只有把防护措施融入到日常的运维流程中,才能在真正的攻击来临时从容应对。
