页面卡顿不一定是服务器配置不够,很多时候是遭遇了CC攻击。CC攻击的流量和正常访问请求高度相似,藏在海量的日志里。运营人员接到用户反馈后,第一反应往往是登录服务器看CPU和带宽,发现负载飙升就重启服务,这恰恰销毁了溯源的第一手证据。正确的做法是先隔离流量,保留现场,然后从网络层和应用层两个维度交叉锁定攻击源IP。
从网络连接状态直接揪出高频IP服务器上执行netstat命令是成本最低、速度最快的溯源手段。CC攻击不管是基于HTTP的GET洪水还是POST慢速攻击,最终都会在服务器上建立大量TCP连接。你需要关注的是SYN_RECV、ESTABLISHED和TIME_WAIT这三种状态的数量。如果某个IP的TIME_WAIT连接数异常高,说明它在短时间内频繁断开又重连,这是典型的短连接攻击特征。具体命令可以这样组合:
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -20
这条命令会统计当前所有连接中,出现频率最高的前20个IP。如果排在前面的IP连接数明显高出其他IP一个数量级,比如第二名只有几十个连接,第一名却有上千个,那基本可以判定为攻击源。但要注意区分真实高并发场景,比如CDN回源节点或者合作方的API调用。判断方法是看这些IP的User-Agent和请求路径是否单一,正常高并发来源通常会有多样化的请求模式。
分析Web服务器日志锁定攻击指纹网络层的统计只能告诉你谁连接多,但无法区分是正常用户还是攻击流量。接下来要进入应用层,从Nginx或Apache的访问日志里提取攻击特征。CC攻击为了达到消耗服务器资源的目的,通常会集中请求某个动态页面、搜索接口或者数据库查询较重的URL。你需要先找到被攻击的目标路径:
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head -10
这条命令统计请求最频繁的URL路径。如果某个本不该有大量访问的接口,比如/api/search或者/wp-login.php,突然出现爆发式增长,那这个路径就是攻击者的目标。确定了目标路径后,再筛选出专门攻击这个路径的IP:
grep "/api/search" access.log | awk '{print $1}' | sort | uniq -c | sort -nr | head -20
这样得到的就是针对特定接口发起洪水请求的IP列表。这些IP往往具备共同特征:请求间隔极短、Referer为空或固定值、User-Agent使用低版本浏览器或脚本库特征。把这些IP和上一步netstat抓出来的高频IP做交叉比对,重叠的部分就是高可信度的攻击源。
通过日志时间戳识别慢速CC攻击不是所有CC攻击都是洪水模式。慢速CC攻击的每个IP请求频率并不高,可能每分钟只有几次,但会长时间维持连接不释放,逐渐耗尽服务器的连接池。这类攻击在netstat里看不出单个IP的异常,需要从日志的时间维度来分析。你可以按分钟统计请求量,观察是否存在持续平稳的低频流量:
awk '{print $4}' access.log | cut -d: -f2,3 | sort | uniq -c | sort -n
如果发现某个时间段内,有大量IP的请求频率高度一致,比如都是每分钟3到5次,且持续超过半小时,这就是典型的慢速攻击调度特征。进一步提取这些IP,看它们的请求时间间隔是否呈现规律性。真正的用户访问会有波峰波谷,而脚本发起的慢速攻击往往是均匀分布的。把这类IP单独拉出来,结合它们的请求内容再做判断,通常能发现攻击者刻意模拟正常行为但忽略了时间分布的随机性。
利用TCP连接的异常特征反向验证日志分析得出的可疑IP列表,还需要通过网络层的连接状态来反向验证,避免误封正常用户。一个有效的方法是检查这些IP的TCP重传率和窗口大小。攻击脚本为了追求发包效率,通常在TCP握手后不等待确认就继续发送数据,导致重传率异常偏高。你可以用ss命令查看特定IP的详细信息:
ss -ti state established dst [可疑IP]
输出中的retrans字段如果数值持续增长,说明这个IP的连接质量很差,大概率是攻击工具发起的。正常用户的TCP重传率一般低于2%,而攻击工具的重传率可能高达10%以上。另一个观察点是TCP窗口大小,攻击脚本往往使用固定且较小的窗口值,而正常浏览器会根据网络状况动态调整。这些网络层的异常特征可以和日志分析结果相互印证,帮你从可疑IP中筛选出真正需要封禁的攻击源。
区分代理IP和真实攻击源CC攻击的发起者很少直接使用自己的真实IP,通常会挂载多层代理或者使用云函数、家庭宽带等动态IP资源。你抓到的IP大概率是某个出口节点的地址。但这并不意味着溯源没有意义,因为你需要封禁的就是这些直接对服务器造成压力的IP。不过在做特征提取时,要注意识别IP的地理分布和归属网络。如果攻击IP集中在某个地区的某个运营商网段,可以考虑对网段做限制而不是逐个封IP。查看IP归属可以用whois命令或者调用本地的IP库接口。如果攻击IP分散在全球各地,但User-Agent高度一致,那说明攻击者使用了分布式的代理池,这时候封IP的效果会很差,需要结合请求特征来做应用层拦截。
实时监控与自动化处置的联动策略手动溯源适合事后分析,但要快速止损,需要建立实时监控和自动封禁的联动机制。你可以在服务器上部署一个轻量级的shell脚本,定时执行netstat统计,当某个IP的连接数超过阈值时自动写入iptables黑名单。但这种方式风险较高,容易误伤NAT网络下的正常用户。更稳妥的做法是结合Web日志做二次判断:脚本发现高频IP后,先不封禁,而是去最近的日志里检索这个IP的请求路径和User-Agent,如果命中已知的攻击特征,再触发封禁。脚本逻辑可以这样设计:
#!/bin/bash
# 获取当前连接数超过100的IP
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr |
while read count ip; do
if [ $count -gt 100 ] && [ "$ip" != "127.0.0.1" ]; then
# 检查日志中该IP最近1分钟的请求特征
ua=$(grep "$ip" access.log | tail -100 | awk -F'"' '{print $6}' | sort | uniq -c | sort -nr | head -1)
# 如果User-Agent单一且为空或包含攻击特征,执行封禁
if echo "$ua" | grep -qE "curl|python|go-http|^-$"; then
iptables -A INPUT -s $ip -j DROP
echo "$(date) Blocked $ip with count $count and UA $ua" >> /var/log/block.log
fi
fi
done
这个脚本只是一个基础示例,生产环境需要根据实际业务调整阈值和特征匹配规则。关键思路是网络层初筛加应用层确认,两道关卡交叉验证,既能快速响应,又能降低误封率。
从攻击模式反推攻击者意图溯源不仅仅是找到IP,更重要的是理解攻击者的目标和方法,这样才能做针对性防御。分析日志时留意攻击请求的具体参数。如果攻击者反复请求搜索接口并传入随机关键词,目的是绕过缓存让每次查询都落到数据库。如果攻击者针对登录接口发起POST请求,可能是尝试撞库而不是单纯的CC。如果请求的URL里带有大量的随机参数或者超长的Cookie,那是在尝试消耗服务器的内存和带宽。把这些攻击特征记录下来,后续可以在WAF或者Nginx层面直接针对这些特征做规则拦截,比单纯封IP有效得多。攻击者更换IP的成本很低,但更换攻击手法的成本相对较高,你的防御策略应该围绕攻击特征而非IP地址来构建。
日志留存与事后深度分析很多运营人员习惯在攻击结束后清理日志释放磁盘空间,这是一个需要调整的做法。完整的攻击日志是优化防御策略的宝贵数据。建议将攻击期间的日志单独备份,事后做离线分析。你可以用GoAccess或者ELK之类的工具对历史攻击日志做聚合分析,找出攻击流量的分布规律、常用的User-Agent库、偏好的攻击时段。这些数据积累下来,就能形成针对你业务的攻击画像。下次再有类似流量特征出现,即使连接数还没达到告警阈值,也能提前预警。日志里还隐藏着攻击者测试防御边界的痕迹,比如攻击前的小流量探测,这些蛛丝马迹往往能帮你提前发现下一波攻击的目标路径。
快速溯源CC攻击源IP的核心思路是网络层和应用层交叉分析,用连接状态找高频来源,用日志特征确认攻击行为,用TCP异常反向验证,最终输出一份高可信度的攻击IP列表。整个过程不需要依赖第三方工具,服务器自带的命令行就能完成绝大部分工作。关键在于保持冷静,先留存证据再动手处理,避免破坏现场导致溯源链断裂。
