网站CC攻击的防御早已不是一次性配置防火墙规则就能解决的问题。攻击者会不断更换代理IP、调整请求频率、伪造User-Agent和Referer,甚至模拟真实用户的鼠标轨迹和停留时间。如果运维团队仍然依赖“告警—封IP—解封”的循环,业务迟早会被拖垮。真正有效的做法是把CC防御纳入日常运维流程,形成一套可观测、可量化、可自动响应的常态化管理机制。
CC攻击与普通DDoS的本质差异
CC攻击的流量通常远小于DDoS,但破坏力更集中。它不靠带宽打满网络,而是用大量看似合法的HTTP请求消耗服务器资源,尤其是数据库连接、PHP进程、API接口和搜索功能。一个电商网站的商品搜索接口,单次请求可能消耗几十毫秒的CPU和数据库查询,攻击者每秒发起几百次请求,就能让数据库连接池耗尽。传统基于IP频率的限制往往误伤NAT出口下的正常用户,比如企业或学校共用出口IP的场景。因此,常态化防御的核心不是“封禁”,而是“识别与分层处置”。
第一步:建立请求基线与行为画像
没有基线就没有异常判断的依据。运维团队需要先对正常业务流量建模。采集至少两周的访问日志,统计每个URL的请求量分布、不同时段的QPS、User-Agent比例、Referer来源、单IP的请求间隔和会话深度。例如一个内容站,正常用户访问首页后可能继续点击3到5个内页,停留时间从几十秒到几分钟不等;而CC攻击脚本往往只请求同一个URL,或者随机抓取几个URL,请求间隔固定且极短。把这些特征量化后,就可以在Nginx或网关层配置动态阈值。
实际运维中,可以基于Nginx的limit_req模块做基础限速,但不要只依赖它。更有效的方式是用Lua脚本或OpenResty在请求进入后端前做行为判断。例如,对单IP的请求间隔做滑动窗口统计,如果连续20次请求间隔小于200毫秒,并且请求的URL集中在少数几个资源上,直接返回444或者跳转到验证码页面。这里的关键是“分层”,而不是一刀切地封IP。
第二步:构建多级防御体系
单点防御很容易被绕过。常态化运维需要把防御拆成边缘层、接入层、应用层和数据层四个级别。
边缘层主要利用CDN和云防火墙。CDN天然能吸收一部分CC攻击,因为攻击请求在边缘节点就被过滤或缓存命中。但要注意,如果源站IP暴露,攻击者可以直接绕过CDN打源站。所以源站必须只允许CDN回源IP访问,同时在云防火墙设置严格的ACL规则。
接入层是Nginx或Apache。这里除了限速,还要配置连接数限制、超时时间调优、禁用不必要的HTTP方法。比如很多CC攻击会使用HEAD请求探测资源,如果业务不需要HEAD,直接返回403。还可以开启Nginx的缓存功能,把静态资源和部分动态页面缓存起来,减少后端压力。
应用层是防御的重点。CC攻击往往针对动态接口,比如登录、搜索、下单、验证码发送等。这些接口必须在代码层面做频率限制和业务风控。例如登录接口,同一账号或同一设备指纹在5分钟内失败超过3次就要求输入图形验证码,超过10次锁定30分钟。搜索接口可以按用户会话或IP做令牌桶限流,同时把搜索结果缓存到Redis,设置3到5秒的过期时间,即使攻击请求穿透到应用层,也不会每次都打到数据库。
数据层则需要监控连接池使用率、慢查询数量和锁等待时间。CC攻击的一个典型特征是数据库连接数突然飙升,但QPS并不高。运维需要设置告警,当连接池使用率超过80%持续1分钟,自动触发应用层的降级策略,比如关闭非核心推荐接口、返回静态兜底页面。
第三步:自动化响应与动态策略
常态化运维不能靠人工盯着日志。必须建立自动化的检测与响应链路。推荐使用ELK或类似日志分析平台,实时采集Nginx访问日志和应用日志,通过规则引擎或机器学习模型识别异常流量模式。一旦触发阈值,自动调用API向CDN或防火墙下发封禁策略,同时通知运维人员。
一个实用的自动化流程如下:
# 伪代码示例:基于日志分析的自动封禁
tail -f /var/log/nginx/access.log | awk '{print $1, $7, $NF}' |
while read ip url status; do
count=$(redis-cli INCR "cc:${ip}:${url}")
redis-cli EXPIRE "cc:${ip}:${url}" 60
if [ $count -gt 100 ]; then
curl -X POST "https://api.cdn.com/block" -d "ip=${ip}&reason=cc"
echo "$(date) Blocked ${ip} for ${url}" >> /var/log/cc_block.log
fi
done
这段代码只是示意,实际生产环境需要更严谨的并发控制和去重逻辑。但核心思路是:用Redis做计数器,按IP和URL维度统计短时间内的请求次数,超过阈值就调用API封禁。封禁时间可以设置阶梯,第一次封10分钟,第二次封1小时,第三次封24小时。同时要设置白名单,避免封掉搜索引擎爬虫或合作方IP。
第四步:验证码与挑战机制
对于无法直接封禁的流量,比如来自大规模代理池的攻击,验证码是有效的第二道防线。但验证码不能全局开启,否则严重影响用户体验。正确的做法是只对可疑流量弹出验证码。判断可疑的标准包括:请求频率异常、缺少常见浏览器特征、Referer为空或与业务无关、Cookie缺失、JavaScript执行失败等。
可以在Nginx层集成Lua脚本,对可疑请求返回一个包含JavaScript挑战的页面。正常浏览器会自动执行JavaScript并携带生成的Cookie重新请求,而简单的攻击脚本不会执行JavaScript,自然被拦截。这种无感验证对用户体验影响很小,但能过滤掉大部分脚本化攻击。
第五步:常态化监控与压力测试
防御策略不是配置完就一劳永逸。业务功能迭代、促销活动、季节波动都会改变流量基线。运维团队需要每月重新评估基线数据,调整阈值。同时定期进行模拟CC攻击演练,验证防御链路是否有效。可以使用ApacheBench、wrk或自研脚本从多台测试机发起请求,观察各层防御是否按预期触发,以及正常用户是否被误伤。
监控指标要覆盖:QPS、响应时间、错误率、连接数、数据库连接池、Redis命中率、封禁数量、验证码弹出率。当封禁数量突然增加但业务流量没有明显变化时,可能是正常用户被误伤,需要检查策略。当验证码弹出率超过一定比例,说明攻击流量较大,需要提升边缘层拦截能力。
第六步:日志留存与溯源分析
每次攻击事件后,都要做复盘。保留至少30天的访问日志,分析攻击源IP的地理分布、AS号、请求特征、攻击时长和峰值QPS。这些数据可以帮助优化防御策略,也可以作为向云服务商或安全厂商提交的情报。如果攻击源集中在某些IDC或云厂商的IP段,可以主动联系对方投诉,或者直接在边缘层对相关AS号做限制。
同时要关注攻击工具的变化。早期的CC攻击工具使用固定User-Agent,现在很多工具会随机生成User-Agent,甚至模拟真实浏览器的TLS指纹。防御策略需要不断更新,不能只依赖简单的字符串匹配。可以考虑引入JA3指纹检测,识别TLS握手特征,区分真实浏览器和脚本工具。
第七步:业务层面的容错与降级
即使防御做得再好,也无法保证100%拦截。因此业务系统本身必须具备容错能力。核心接口要做熔断和降级,当后端压力过大时,优先保证登录、下单、支付等关键流程,关闭评论、推荐、排行榜等非核心功能。页面可以静态化,把动态内容通过定时任务生成静态HTML,攻击时直接返回静态页面,减少后端计算。
数据库层面要做好读写分离和缓存预热。CC攻击往往导致缓存穿透,大量请求直接打到数据库。可以通过布隆过滤器拦截不存在的Key,或者对热点数据做多级缓存。如果数据库已经过载,要能快速切换到从库或限流模式,保证服务不崩溃。
常态化运维的落地清单
把上述内容整理成可执行的日常任务,建议运维团队按以下节奏推进:每日检查封禁日志和告警记录,确认是否有误伤;每周分析流量基线变化,调整限速阈值;每月进行一次模拟攻击演练,验证防御链路;每季度更新一次User-Agent黑名单和IP信誉库;每年对整体架构做一次安全审计,评估是否需要引入专业抗CC设备或服务。
CC攻击防御的难点在于攻击成本极低,而防御成本相对较高。常态化运维的目标就是通过自动化手段把防御成本降下来,同时把攻击者的成本提上去。当攻击者发现无法用简单脚本打垮目标,需要投入更多代理资源和时间时,自然会转向其他目标。这本身就是一种有效的威慑。
