CC攻击(Challenge Collapsar)的本质不是拼带宽,而是拼资源。攻击者通过控制大量代理服务器或肉鸡,向目标网站发起大量看似合法的请求,这些请求专门瞄准数据库查询、动态页面生成、搜索功能、登录接口等消耗服务器CPU和内存的环节。一个配置普通的服务器,可能几百个并发请求就能把连接数占满、数据库连接池耗尽,导致正常用户无法访问。防御CC攻击的核心思路不是“挡住所有流量”,而是“把资源留给真实用户”,同时用最低的成本识别并丢弃恶意请求。

先区分攻击类型,才能对症下药

CC攻击大致分为三种:直接攻击源站、攻击动态页面、模拟真实用户行为。第一种最常见,攻击者直接对网站首页或某个URL发起海量请求;第二种专门挑搜索、登录、注册、购物车这类需要后端计算的页面下手,因为这类页面一次请求可能消耗几十倍于静态页面的资源;第三种更隐蔽,攻击者会伪造User-Agent、Referer、Cookie,甚至模拟鼠标点击和停留时间,让请求看起来和真人无异。很多网站被打了半天才发现,是因为把第三种攻击当成了正常流量高峰。

判断自己是否正在遭受CC攻击,可以看几个指标:服务器负载突然升高但带宽没跑满;网站数据库连接数异常增长;Nginx或Apache日志里同一时间段出现大量相同URL的请求;正常用户反馈页面打开极慢或频繁出现502/504错误。如果这几个现象同时出现,基本可以确定是CC攻击。

第一层防御:Web服务器层做请求限制

Nginx和Apache本身就有模块可以做基础的频率限制。Nginx的ngx_http_limit_req_module可以针对单个IP限制请求速率,配置示例如下:

http {
    limit_req_zone $binary_remote_addr zone=cc_limit:10m rate=10r/s;
    
    server {
        location / {
            limit_req zone=cc_limit burst=20 nodelay;
        }
    }
}

这段配置的意思是:以客户端IP为键,分配10MB的共享内存区域,限制每个IP每秒最多10个请求,允许突发20个请求,超过部分直接返回503而不延迟处理。但这种方法有明显的局限:如果攻击者使用了大量代理IP,每个IP的请求频率都不高,单IP限频就失效了。另外,如果公司或学校出口共用同一个公网IP,正常用户也会被误伤。所以IP限频只能作为第一道粗筛,不能作为主要防御手段。

Apache用户可以用mod_evasive模块实现类似功能,但Apache本身是进程模型,在高并发下性能不如Nginx,建议在Apache前面再挂一层Nginx做反向代理和限流。

第二层防御:识别恶意特征,精准拦截

真正的CC防御不能只靠IP频率,要结合请求特征做多维判断。攻击请求和正常请求在细节上往往有差异,关键是要找出这些差异并配置规则。

检查User-Agent:很多CC攻击脚本使用默认的UA,比如python-requests、curl、空UA或者非常老旧的浏览器版本。可以在Nginx中直接拒绝这些UA:

if ($http_user_agent ~* "python-requests|curl|wget|libwww-perl|^$") {
    return 444;
}

检查Referer:如果某个页面正常情况下只能从站内跳转访问,但日志里出现大量无Referer或Referer来自陌生域名的请求,这些大概率是攻击流量。比如登录接口、注册接口、搜索接口,正常用户一定是从站内页面发起的。

检查Cookie:真实浏览器访问动态页面时会携带完整的Cookie,而很多CC攻击脚本不处理Cookie或者Cookie值固定不变。可以设置一个验证Cookie机制:用户第一次访问时,服务器返回一个带有特定Cookie值的响应,同时要求客户端带上这个Cookie重新请求。攻击脚本如果不处理Cookie,就会被拦截。这个思路后来发展成了JavaScript跳转验证,也就是很多CDN服务商使用的“浏览器验证”功能。

第三层防御:动态页面静态化与缓存

CC攻击最怕的不是请求多,而是每个请求都打到后端动态程序上。如果把动态页面变成静态文件,或者把动态响应缓存起来,攻击请求就变成了对缓存文件的读取,服务器压力会下降一个数量级。

对于内容更新不频繁的页面,可以直接生成静态HTML文件,用户访问时由Nginx直接返回文件,完全不经过PHP、Java或数据库。对于必须动态生成的页面,可以在Nginx层配置反向代理缓存:

proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=page_cache:50m max_size=1g inactive=60m use_temp_path=off;

server {
    location / {
        proxy_cache page_cache;
        proxy_cache_key "$scheme$request_method$host$request_uri";
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
        proxy_pass http://backend;
    }
}

这样配置后,同一个URL在缓存有效期内只会请求一次后端,后续请求全部命中缓存。攻击者即使发起大量请求,消耗的也只是Nginx的并发处理能力和磁盘IO,不会打到数据库。需要注意的是,登录状态下的页面、购物车、用户中心等个性化内容不能无差别缓存,否则会导致用户数据串号。这类页面要根据Cookie中的会话标识做缓存键区分,或者干脆不缓存,用其他方式保护。

第四层防御:验证码与行为验证

当攻击请求已经伪装得很像正常用户时,最有效的办法是引入人机验证。传统图形验证码体验较差,容易流失用户,现在更常用的是行为验证,比如滑动拼图、点击指定区域、无感验证等。这类验证的原理是在前端收集鼠标轨迹、设备指纹、浏览器环境信息,发送到验证服务端进行风险判断。攻击脚本通常不具备完整的浏览器渲染能力和真实的人类操作行为,很难通过验证。

部署方式上,可以在Nginx层集成验证模块,对可疑请求先返回验证页面,验证通过后发放一个短期有效的Token Cookie,后续请求携带该Cookie才能访问真实内容。Token有效期可以设置为5到15分钟,过期后重新验证。这样既不会频繁打扰正常用户,又能有效拦截自动化攻击。

第五层防御:利用CDN和云防护服务

对于流量规模较大的CC攻击,单靠源站自己扛是不现实的。CDN服务商的节点遍布全球,拥有海量带宽和清洗能力,可以把攻击流量分散到各个节点上,源站只接收经过过滤的干净流量。国内主流的云防护服务都提供CC攻击防护功能,它们会在边缘节点上做请求频率限制、特征识别、人机验证、IP信誉库匹配等一系列动作。

使用CDN防护时要注意几个细节:源站IP不要暴露,否则攻击者可以绕过CDN直接打源站;CDN的回源地址要做白名单,只允许CDN节点访问;如果网站有WebSocket或长连接需求,要确认CDN支持这类协议,否则正常功能会受影响。另外,CDN的缓存策略要和源站配合好,把能缓存的页面尽量缓存到边缘节点,减少回源请求。

第六层防御:后端应用层的资源保护

即使前面几层都做了,仍可能有部分攻击请求穿透到后端应用。这时候后端程序自身也要有保护机制。数据库连接池要设置合理的最大连接数和超时时间,避免被慢查询或恶意查询占满。对于搜索、列表、报表这类高消耗接口,要单独做频率限制和结果集大小限制。比如搜索接口限制每个用户每分钟最多请求20次,单次返回结果不超过100条。登录接口要做失败次数锁定,防止攻击者用CC方式暴力破解账号。

应用层还可以引入异步处理和消息队列。对于非实时性要求的操作,比如发送邮件、生成报表、数据导出,可以先接收请求放入队列,由后台任务慢慢处理,前端立即返回“任务已提交”。这样即使攻击者大量提交任务,也只是往队列里塞消息,不会立刻消耗大量计算资源。队列满了之后直接拒绝新任务,保护核心服务不受影响。

第七层防御:日志分析与自动化响应

被动防御总有疏漏,主动发现攻击特征并自动化响应才是长期方案。通过分析Nginx访问日志,可以实时统计每个IP的请求数、每个URL的请求频率、User-Agent分布、状态码比例等指标。当某个指标异常时,自动触发防护策略,比如临时封禁某个IP段、对某个URL启用更严格的限流、或者把可疑流量导入验证页面。

一个简单的实现方式是使用Fail2ban配合Nginx日志。Fail2ban可以监控日志文件,根据正则规则匹配恶意请求,自动调用防火墙命令封禁来源IP。配置示例如下:

[nginx-cc]
enabled = true
filter = nginx-cc
action = iptables-multiport[name=nginx-cc, port="http,https", protocol=tcp]
logpath = /var/log/nginx/access.log
maxretry = 100
findtime = 60
bantime = 600

这段配置的含义是:60秒内同一个IP出现100次匹配规则的请求,就封禁该IP 10分钟。规则本身可以根据实际情况调整,比如匹配特定URL、特定状态码、特定UA等。对于更复杂的场景,可以自己写脚本解析日志,结合Redis做实时计数,达到阈值后调用云服务商的API进行封禁。

防御CC攻击的常见误区

很多人以为加带宽就能防住CC攻击,实际上CC攻击消耗的是服务器计算资源,带宽再大也扛不住数据库被拖垮。还有人把所有防护都寄托在防火墙层面,但传统防火墙主要工作在OSI第三层和第四层,对应用层的CC攻击识别能力有限。另外,过度依赖IP黑名单也不现实,攻击者可以随时更换IP,黑名单更新速度永远跟不上攻击变化。

另一个容易被忽视的问题是“防御误伤”。有些网站为了防CC,把限流阈值设得极低,结果正常用户多开几个页面就被拦截,搜索引擎爬虫也被拒之门外。防御策略要在安全和可用性之间找平衡,建议对搜索引擎爬虫做白名单放行,对已知的合法代理IP做信任处理,对普通用户采用渐进式验证而不是一刀切拦截。

构建多层防御体系才是根本

单靠某一层防御无法应对复杂的CC攻击,真正有效的方案是把前面提到的各层手段组合起来。第一层用Nginx限频和UA过滤挡住最粗糙的攻击脚本;第二层用Referer和Cookie校验识别伪造请求;第三层用页面缓存和静态化降低后端压力;第四层用行为验证拦截高度拟人化的攻击;第五层用CDN分散流量并提供边缘清洗;第六层在后端应用做好资源隔离和限流;第七层通过日志分析实现自动化响应。这七层相互配合,攻击者突破任何一层,后面还有多层防线等着。

最后要强调的是,CC攻击的形态一直在变化,攻击者会不断研究新的绕过手段。网站运维人员需要定期复盘攻击日志,分析攻击特征的变化趋势,及时调整防护规则。防御不是一次配置就一劳永逸的事情,而是一个持续对抗和迭代的过程。把基础架构搭好、把监控告警做全、把响应流程理顺,才能在攻击发生时快速恢复服务,把对正常用户的影响降到最低。