服务器遭遇高CC攻击导致CPU 100%的应急排查与防护五步法

CC攻击(Challenge Collapsar)是一种应用层DDoS攻击,通过大量合法请求耗尽服务器资源,导致CPU飙升至100%。本文提供一套经过实战验证的五步应急方案:从快速定位攻击源、临时阻断、日志溯源,到永久防护策略调整与事后复盘。无需昂贵的硬件防火墙,纯软件手段即可在10分钟内止血。

服务器遭遇高CC攻击导致CPU 100%的应急排查与防护五步法
封面图:ZuCDN · ZuCDN 原创

前言:当CPU曲线突然拉满,你只有几分钟

CC攻击的可怕之处在于它不像SYN Flood那样立刻让端口瘫痪,而是让服务器缓慢窒息——CPU稳步爬升到100%,网站响应变得像在泥潭里跑步。你登录SSH时可能已经卡得敲不下命令,而攻击者正用成百上千个代理IP刷着你站点最耗资源的接口(比如搜索、登录、报表生成)。

本文不会讲“什么是CC攻击”这种基础概念,而是直接给出你此刻最需要的东西:一套从发现异常→定位攻击→临时阻断→根源分析→加固防护的闭环操作五步法。每一步都附带可执行的命令和可验证的结果,不忽悠、不绕弯。

第一步:快速确认——到底是CC攻击还是程序BUG

CPU 100%不一定都是攻击,也有可能是代码死循环、数据库慢查询、爬虫暴增。你需要用最快速度做两个动作来定性。

1.1 查看实时进程,锁定CPU消耗大户

SSH登录后立刻执行(如果ssh卡顿,尝试重启sshd或使用串口控制台):

top -c -b -n 1 | head -50

重点关注%CPU列,如果排在前面的都是Apache/Nginx/PHP-FPM worker进程,并且每个worker都显示处理同一个URI(比如/?id=1&page=1之类的重复请求),那基本可以断定是CC攻击。如果消耗最高的是mysqld,且SQL查询时间很长,则更可能是慢查询或缓存失效。

1.2 查看网络连接状态,寻找大量ESTABLISHED

执行:

netstat -ant | grep :80 | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

正常情况下,来自同一个IP的连接数不会超过几十个。如果看到大量来自不同IP但连接数接近(比如每个IP只有3-5个连接,但总连接数上千),并且这些IP分布在不同C段,说明正在遭受分布式CC攻击。如果攻击IP来自少数几个C段,也可能是单点代理攻击。

第二步:紧急止血——在不扩容硬件的前提下快速阻断

确认是CC攻击后,你的首要目标不是抓黑客,而是让CPU降下来。以下是风险最低、见效最快的临时方案。

2.1 使用iptables临时封禁可疑IP段

如果攻击IP集中在某几个C段,直接封禁该段:

iptables -A INPUT -s 192.168.1.0/24 -j DROP

注意:在封禁前请确认这些IP不是你的CDN节点或合法爬虫。如果无法确认,建议先限速而非直接DROP:

iptables -A INPUT -s 192.168.1.0/24 -m limit --limit 5/s -j ACCEPT
iptables -A INPUT -s 192.168.1.0/24 -j DROP

2.2 利用Nginx的limit_req限制请求频率

大多数CC攻击针对特定URI(如登录页面、API接口),可以在Nginx的server或location块中增加:

limit_req_zone $binary_remote_addr zone=cc:10m rate=30r/m;
server {
    location /api/ {
        limit_req zone=cc burst=5 nodelay;
        proxy_pass http://backend;
    }
}

这里rate=30r/m表示每分钟最多30次请求,burst=5允许瞬间突发5次。请根据正常业务流量调整参数。配置后重新加载nginx:nginx -s reload。CPU会立刻下降,因为大量超额请求在Nginx层就被拒绝了。

2.3 临时切换为静态页面或开启CDN缓存

如果上面两步没能让CPU降到80%以下,最粗暴的方法:将动态请求临时重定向到一个静态HTML(比如维护页面)。在Nginx配置中:

location / {
    if (-f $uri) { break; }
    rewrite ^ /maintenance.html break;
}

同时联系CDN服务商开启全站缓存。攻击过去后再恢复原配置。

第三步:深度排查——从日志中揪出攻击特征

CPU降下来之后,你需要搞清楚攻击者到底在刷什么,才能做针对性防护。

3.1 分析access.log,统计高频请求URI

切换到Nginx日志目录:

cd /var/log/nginx/
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -20

如果排第一的URI请求次数是第二名的几十倍,且该URI是动态接口(如/api/user/login),攻击目标就是它。记录下该URI。

3.2 分析User-Agent和Referer

执行:

awk -F'"' '{print $6}' access.log | sort | uniq -c | sort -rn | head -10

如果User-Agent都是相同的随机字符串或很老的浏览器版本(如Mozilla/4.0),说明是工具发包。可以在Nginx中直接屏蔽该User-Agent:

if ($http_user_agent ~* "Mozilla/4.0") { return 403; }

但注意:不要轻易屏蔽真实用户的UA,建议先对可疑UA进行限速。

3.3 检查PHP-FPM慢日志

如果攻击触发了PHP执行,慢日志能告诉你哪个脚本执行时间异常:

tail -f /var/log/php-fpm/slow.log

通常会发现攻击者反复请求一个执行时间超过1秒的函数(如文件写入、复杂计算)。考虑对那个函数增加频率限制或引入队列异步处理。

第四步:建立长效防护——让相同的手法失效

应急搞定后,必须把临时措施升级为永久规则。

4.1 加入WAF规则(ModSecurity或云WAF)

推荐使用ModSecurity的OWASP CRS规则集,对CC攻击有现成的规则(如922100检测请求速率)。但是开箱即用容易误伤,需要先设置为DetectionOnly模式观察一段时间。云WAF(如Cloudflare、阿里云WAF)的CC防护更智能,建议直接购买专业版。

4.2 设置连接数限制(连接池)

在Nginx中,针对每个客户端IP设置最大连接数:

http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    server {
        location / {
            limit_conn addr 10;
        }
    }
}

注意:如果使用了CDN,$binary_remote_addr会来自CDN节点IP,需要改为$http_x_forwarded_for或CDN提供的真实IP变量。

4.3 引入验证码/滑块验证

对于登录、注册、搜索等高危接口,增加验证码(Google reCAPTCHA或hCaptcha)是最有效的硬性拦截。攻击脚本无法通过验证码,但用户体验会受影响。更折中的方案是:当同一IP在短时间内请求超过阈值时,才弹出验证码。

4.4 架构层面做动静分离

确保所有静态资源(图片、CSS、JS)都通过CDN分发,不要让动态服务器处理静态请求。同时将动态请求中可以被缓存的接口(如新闻列表)使用Redis或Varnish做全页缓存,减少PHP/数据库压力。

第五步:事后复盘——建立标准化响应SOP

攻击结束后,写下这次事件的详细记录:攻击时间、攻击IP列表、攻击URI、采取的阻断措施、CPU恢复时间、后续永久防护配置。这些数据可以用来优化监控告警。

5.1 告警阈值调优

设置CPU和连接数的监控告警(建议CPU>80%持续5分钟告警,ESTABLISHED连接数>5000告警),避免下次被动发现。可以使用Netdata或Prometheus+Alertmanager。

5.2 定期演练

在测试环境模拟CC攻击(可以使用wrk或ab工具),验证防护规则是否有效。确保团队每个人都知道SSH备用入口、iptables临时封禁命令、Nginx限频配置修改位置。

5.3 考虑上高防IP或流量清洗

如果CC攻击频率高(每月1次以上),建议接入高防IP服务(如阿里云高防、腾讯云大禹),它们有专门的CC防护引擎,能识别并清洗异常流量。

写在最后:没有银弹,但有经验

CC攻击防护没有一劳永逸的方案,因为攻击手法也在进化。本文的五步法帮你建立了一个快速响应-深度分析-永久加固-复盘改进的闭环。关键是每一步都要有可验证的结果:限速后CPU是否下降、封禁后连接数是否减少、日志中特征是否消失。下次再遇到CPU 100%,你可以从容应对。

延伸阅读