前言
前段时间网站出了个怪事,访问量没涨,CPU却突然跑满,带宽看着也正常,但页面开始频繁超时,连正常用户都进不来 😭 我一开始以为是程序出了bug,查了日志、看了数据库、排查了插件,折腾了三天,最后才发现是CC攻击。今天就分享一下这个排查过程,给同样遇到CPU莫名跑满的朋友一个参考。
一开始我以为是程序问题
网站出问题的第一天,第一反应是程序出bug了。因为访问量没变化,服务器配置也没动过,突然就变慢,很像是某个插件更新导致的。
我先看了后台,插件版本都正常,没有报错。又看了PHP错误日志,没有致命错误,只有一些警告。数据库查询看起来也不慢,慢查询日志里没有明显异常。
这时候CPU使用率已经持续在90%以上,但带宽只用了不到10%。这个比例有点奇怪。如果是正常流量增长,带宽和CPU应该一起涨。现在带宽没动,CPU却跑满,说明问题不在流量大小,而在请求的处理成本。
第二天开始查请求日志
第二天我开始认真看Nginx的访问日志。
正常用户的请求,间隔比较均匀,URL分布也比较分散。但我发现日志里有大量请求集中在几个动态接口上,比如搜索页、登录页、评论提交接口。这些请求的间隔非常短,有的同一秒内几十次,而且来源IP很分散,不是单一IP。
这就是CC攻击的典型特征。它不打带宽,而是打你的动态处理能力。每次请求都要经过PHP、查数据库、返回结果,CPU和数据库连接被这些低价值请求持续消耗,正常用户的请求反而排不上队。
CC和DDoS的区别也在这里。DDoS通常是流量洪水,打的是网络带宽。CC打的是应用层,流量可能不大,但请求处理成本高,源站照样被拖垮。
第三天确认并临时止血
确认是CC之后,我先做了几件临时止血的事。
封禁高频IP段:从日志里筛出请求频率异常高的IP和IP段,先在防火墙层面封掉。攻击者用了不少代理IP,封禁只能挡住一部分,但能争取时间。
给动态接口加Rate Limiting:在Nginx里对搜索、登录、评论这些接口加限流,同一IP在短时间内超过阈值就返回429。
开启缓存:把能缓存的页面和资源尽量缓存,减少回源到PHP的请求量。缓存命中率一上去,CPU立刻降了不少。
上WAF规则:拦截明显的异常请求特征,比如特定的User-Agent、异常的请求参数、高频的POST请求。
这几步做完,CPU从90%以上降到40%左右,网站恢复了正常访问。但这只是临时止血,攻击者换一批IP、换一种请求方式,可能还会再来。
为什么带宽正常也会被打挂
这次经历让我彻底理解了CC攻击的逻辑。
CC攻击攻击的不是带宽,是处理能力。 一个动态请求可能要查数据库、跑PHP逻辑、渲染页面,消耗的CPU和数据库连接远大于一个静态资源请求。攻击者用大量这类请求,让源站持续做低价值工作,正常请求就被挤出去了。
所以判断CC攻击不能只看带宽。更值得关注的是:单位时间内有多少请求到达,以及每个请求需要源站处理多少工作。
带宽正常但CPU跑满,页面超时但网络没堵,这种情况大概率就是CC,不是正常流量增长。
该怎么长期防护
临时止血之后,我开始考虑长期防护。单靠封IP和限流不够,攻击者会换IP、换特征。真正要解决的是把请求处理尽可能前移,让能在边缘解决的问题不要继续传给源站。
思路大概是这几层:
缓存层:图片、CSS、JS、静态页面全部走缓存,减少回源。
限流层:对动态接口做Rate Limiting,限制单IP和单接口的请求频率。
WAF层:拦截异常请求特征,识别攻击模式。
CDN层:把请求先引到边缘节点,缓存命中直接返回,异常请求在边缘限制,只有真正需要实时处理的请求才回源。
源站保护:限制源站访问来源,只允许可信节点访问,避免攻击者绕过CDN直连源站。
这几层配合起来,源站压力才能真正降下来。
总结
网站CPU突然跑满、带宽却正常,这种情况很可能是CC攻击。排查思路是先看请求日志,找异常高频的动态接口请求,确认是不是应用层攻击。确认是CC攻击后,可以靠封IP、限流、开缓存、上WAF规则等方法临时止血,长期防护就要靠CDN把请求处理前移,再加上源站访问来源限制。确认网站状态时,不要只盯着带宽看,CC攻击打的是源站处理能力,不是网络流量。
下一篇我准备写具体怎么在VPS上配置这层防护,如果你也想自己动手给网站加一层防护,可以留意一下❥(^_-)。
推荐阅读:
