企业官网遭遇高并发CC攻击时,最直观的表现不是带宽跑满,而是服务器CPU和数据库连接数瞬间飙升,正常用户请求被大量看似合法的恶意请求淹没。解决这个问题的核心思路,不是堆硬件,而是分层过滤、主动识别、动态清洗。第一层要做的是在边缘节点就把明显异常的流量挡掉,而不是让所有请求都打到源站再处理。

基于请求特征的前置过滤策略

前置过滤是性价比最高的防护手段。在Web服务器层面,Nginx可以通过map模块和limit_req模块组合,对特定路径实施精准速率限制。比如官网的搜索接口、登录接口、注册接口往往是攻击重灾区,需要单独配置限制策略。下面是一段Nginx配置示例,针对搜索接口做每秒5次的限制,超过则返回503:

http {
    limit_req_zone $binary_remote_addr zone=search_zone:10m rate=5r/s;
    
    server {
        location /api/search {
            limit_req zone=search_zone burst=3 nodelay;
            limit_req_status 503;
            proxy_pass http://backend;
        }
    }
}

但单纯按IP做速率限制在CC攻击面前不够用,因为攻击者会使用大量代理IP轮换。更有效的方式是结合请求头指纹做过滤。正常的浏览器请求会携带完整的User-Agent、Accept-Language、Accept-Encoding等头信息,而多数CC攻击工具发起的请求这些头部要么缺失要么格式固定。可以在Nginx中直接拒绝不符合正常浏览器特征的请求:

location / {
    if ($http_user_agent = "") {
        return 444;
    }
    if ($http_accept ~* "text/html") {
        set $valid_browser 1;
    }
    if ($valid_browser != 1) {
        return 444;
    }
}

这里用444状态码直接关闭连接,不返回任何响应,比403更节省资源。同时要注意,有些合法的API调用方可能没有完整浏览器头,需要为API接口单独设置白名单规则,避免误杀。

动态令牌验证机制的落地

前置过滤能挡掉大约60%的低级攻击,但针对模拟完整浏览器行为的CC攻击,需要引入动态令牌验证。原理是在页面中嵌入JavaScript生成的一次性令牌,每次请求时携带该令牌,服务端验证通过后才放行。这种做法对攻击工具来说成本极高,因为攻击脚本通常不会解析执行JavaScript。

实现上,可以在Nginx层面用Lua脚本做令牌的生成与校验。当用户首次访问时,返回一个包含JS挑战的中间页面,JS计算完成后带着令牌重新请求,验证通过后将IP加入白名单并设置过期时间。OpenResty框架很适合做这类逻辑,核心代码思路如下:

access_by_lua_block {
    local redis = require "resty.redis"
    local red = redis:new()
    red:connect("127.0.0.1", 6379)
    
    local token = ngx.var.cookie_token
    local ip = ngx.var.remote_addr
    
    if not token then
        -- 没有令牌,返回JS挑战页面
        ngx.header.content_type = "text/html"
        ngx.say([[]])
        ngx.exit(200)
        return
    end
    
    local cached = red:get("valid_token:" .. ip)
    if cached ~= token then
        -- 令牌无效,重新挑战
        ngx.exit(403)
    end
}

这套机制的关键在于令牌的生成算法要有足够的复杂度,建议结合时间戳、IP地址、服务端密钥做哈希,并且令牌有效期控制在5到10分钟。攻击者即便抓包拿到了令牌,也会很快过期。同时要注意,搜索引擎爬虫和移动端APP访问需要特殊处理,可以针对已知的爬虫UA或APP的固定特征做白名单放行,避免影响正常收录和用户体验。

全站静态化与缓存分层架构

对于企业官网,大部分页面内容对未登录用户来说是相同的,这正是CC攻击防护的天然优势。把动态页面静态化,或者用CDN边缘缓存把请求终结在离用户最近的节点,源站压力会呈指数级下降。具体做法是,对于产品展示页、新闻资讯页、关于我们这类不频繁变动的页面,直接生成静态HTML文件推送至CDN,设置较长的缓存时间。

对于需要动态数据的页面,比如带有用户评论、实时库存信息的页面,可以采用ESI(Edge Side Includes)技术做局部动态化。CDN节点缓存页面主体框架,动态部分通过异步请求回源获取。这样即使攻击者疯狂刷新页面,打到源站的也只是少量动态接口,而动态接口本身又可以做前面提到的速率限制和令牌验证。

在源站层面,还需要做好多级缓存。Nginx的proxy_cache可以缓存后端动态接口的响应,配合Redis缓存数据库查询结果。一个典型的缓存策略是:首页缓存1分钟,列表页缓存5分钟,详情页缓存30分钟。缓存键的设计要包含URL和关键参数,避免缓存污染。当CC攻击发生时,大量请求直接命中Nginx缓存层,根本不穿透到应用服务器和数据库,这是最彻底的防护方式。

IP信誉库与行为分析联动

基于规则的防护总有滞后性,需要引入IP信誉库做主动防御。可以对接开源的IP威胁情报数据,或者使用云厂商提供的IP画像服务。在Nginx的access阶段,查询请求来源IP是否在威胁库中,如果是恶意IP直接拒绝连接。这个查询必须用本地内存缓存,不能每次请求都远程调用,否则查询本身就成了性能瓶颈。

更进阶的做法是行为分析。正常用户访问官网,会有浏览首页、点击导航、查看详情页、停留一段时间这样的行为链路。而CC攻击的请求往往是单一URL的高频访问,或者随机遍历大量URL但每个页面停留时间极短。通过在页面中嵌入埋点脚本,收集用户的鼠标移动、页面滚动、停留时长等行为数据,回传到分析引擎做实时评分。评分低于阈值的IP自动加入黑名单,这个过程可以在秒级完成。

行为分析引擎的架构上,建议用Kafka承接前端埋点数据流,Flink做实时计算,结果写入Redis供Nginx查询。这套链路虽然复杂,但对于金融、电商等高价值官网来说,是识别高级CC攻击的有效手段。需要注意的是,行为埋点不能影响页面加载性能,埋点脚本要异步加载,数据上报用post方式且合并批量发送。

架构层面的弹性扩容与隔离

防护策略再完善,也需要架构上有足够的弹性来吸收攻击流量。企业官网应该采用动静分离的部署架构,静态资源走独立的域名和CDN,动态服务部署在负载均衡后面,并且配置弹性伸缩策略。当CPU使用率持续超过70%时自动扩容新的应用服务器节点,攻击结束后自动缩容。

数据库层面,读多写少的官网场景天然适合读写分离。配置一主多从的数据库集群,从库可以按需弹性增加。CC攻击往往会产生大量数据库查询,读请求分散到多个从库上,能有效避免数据库连接池被打满。同时,对核心业务表要做好索引优化,避免攻击者利用慢查询拖垮数据库。开启数据库的查询缓存或者使用Redis做查询结果缓存,也能大幅提升抗压能力。

还有一个容易被忽视的点是域名解析层面的隔离。将官网域名同时接入多家CDN厂商做互为备份,当一家CDN的防护能力被突破时,可以通过DNS智能解析快速切换流量到另一家。这种多CDN调度策略需要提前做好灾备演练,确保切换过程对用户无感知。

日志监控与自动化响应闭环

防护体系的最后一环是监控和自动化响应。需要实时监控Nginx的499、502、503、504状态码比例,这些状态码突然增多通常意味着后端处理能力不足或者攻击正在进行。同时监控应用服务器的CPU负载、内存使用率、网络连接数等指标,设置合理的告警阈值。

自动化响应脚本可以在检测到异常时,自动执行预设的防护策略。比如当某个IP的请求频率超过阈值时,自动调用iptables或云防火墙API将该IP加入黑名单。当某个接口的响应时间超过2秒时,自动对该接口开启更严格的速率限制。这些操作可以通过Prometheus监控指标触发Alertmanager告警,再由Webhook调用自动化脚本执行。

日志分析方面,建议把Nginx访问日志实时写入Elasticsearch,用Kibana做可视化分析。攻击发生时,可以快速聚合出攻击来源IP、攻击目标URL、攻击请求特征等关键信息,为调整防护策略提供数据支撑。事后还可以用这些日志数据训练机器学习模型,提升行为分析的准确率。

整套方案从边缘过滤到源站缓存,从令牌验证到行为分析,从架构弹性到监控闭环,层层递进形成纵深防护体系。企业官网的CC攻击防护不是一次性配置就能高枕无忧,需要持续根据攻击手法的变化调整策略,定期做压力测试验证防护效果,才能真正在高并发场景下保障业务稳定运行。