ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Linux服务器DDoS攻击检测:从流量分析到应急处理全流程

Linux服务器DDoS攻击检测:从流量分析到应急处理全流程 先交代一下背景这篇文章不是讲怎么发起DDoS而是从运维视角讲清楚“怎么判断自己的Linux服务器是不是正在被打”。我入行那会儿最怕半夜收到告警业务访问卡成PPT领导劈头盖脸一句“是不是被攻击了”结果流量图、连接数、日志翻了一圈压根判断不出来个所以然。后来踩坑多了慢慢总结出一套从“感觉异常”到“确认攻击”再到“定位类型”的检查流程整套流程基本在几分钟内就能跑完。今天就把这套方法完整拆一遍新手照着做也能快速判断老手看过之后也可以查漏补缺。可能有人会问DDoS攻击不是应该靠机房防火墙或者云服务商的高防去抗吗怎么还需要自己在服务器上判断道理是这么个道理但实际情况是大部分小团队、自建机房的服务器根本等不到安全设备触发告警往往是先感受到业务变慢、CPU飙升、带宽打满才后知后觉去查。再者即便是上了高防也需要自己在服务器上确认“攻击是否已经绕过防护打到了源站”这就要靠系统层面的检测手段来回答了。1. 判断DDoS攻击前的必懂基础1.1 DDoS到底在攻击什么三类主流手法与特征DDoS分布式拒绝服务的最终目的只有一个让正常用户访问不到你的服务。但实现这个目的的手法差别很大检测时看的指标也完全不同。第一类是流量型攻击典型代表是UDP Flood和ICMP Flood。这类攻击靠海量报文直接打满服务器带宽让正常请求进不来。判断特征是带宽监控瞬间飙高但服务器的CPU和内存未必有明显变化因为大部分报文在协议栈就丢掉了。第二类是连接型攻击最典型的就是SYN Flood。攻击者不断发送TCP连接请求但不完成三次握手把服务器的半连接队列占满导致新连接无法建立。这类攻击对带宽的消耗未必很大但服务器会表现出明显的“端口能通但业务死活连不上”的症状同时在系统连接表里能看到大量SYN_RECV状态的连接。第三类是应用层攻击也就是常说的HTTP Flood或CC攻击。这类攻击伪装得像真实用户持续发起HTTP请求占满应用连接和线程。特征是服务器的CPU使用率常年居高不下应用日志刷得飞快网络层连接数看起来也“正常得异常”。明白了这三类你就知道为什么只看一个指标容易误判了。流量高不一定是攻击连接多也不一定是攻击必须结合几个维度交叉验证。1.2 判断前先做三件事确认网络、确认业务、确认时间线在敲第一条检测命令之前我强烈建议你先做三件基础确认。第一确认本机网络是否可达。不用搞复杂直接ping一下网关或公网地址如果本机ping出去都丢包说明链路或带宽已经有问题了如果ping正常但业务端口连不上那问题更可能出在连接层或应用层。第二确认业务异常的具体表现。是页面打开极慢还是直接超时连不上是只有某个接口异常还是整个站点都挂了这些描述直接决定你接下来重点查网络层还是应用层。第三确认异常出现的时间线。从什么时候开始卡的在此之前有没有做过变更、发过版本、改过防火墙规则很多所谓的“被攻击”其实就是发布脚本把nginx配置搞坏了或者防火墙规则误封了IP段。把时间线拉出来对比监控图很多疑似攻击其实当场就能排除。这三件事做完你手头就有了四个关键信息网络通不通、业务表现是什么、异常起点在什么时间、变更窗口是否重叠。接下来再用命令去验证才不至于瞎猜。2. 五分钟快速判断从“疑似异常”到“确认攻击”2.1 第一眼看流量与负载把“感觉”变成“数据”先把“感觉服务器变慢了”转换成可对比的数据。登录服务器后我习惯同时开两个终端一个跑top看负载和CPU另一个跑iftop或者nload看实时流量。先看top重点关注load average和CPU的us用户态占用、sy内核态占用、waI/O等待三个指标。如果是应用层攻击us通常会被打到接近100%如果是连接型攻击sy可能偏高因为内核在拼命处理SYN报文和释放超时连接如果完全没事但网络卡那带宽可能已经被流量型攻击打满了。再看实时流量命令示例如下# 实时流量监控按流量降序排列 iftop -i eth0 -n -N -P # 或者用更轻量的工具 nload eth0这里有个关键判断点iftop里会显示当前总流量和每个连接的流量排序。正常业务即使高峰时段流量分布也应该是比较均匀的极少数大连接吃大头。如果看到的是一堆未知IP同时往外或往内灌流量而且每个IP的流量都不小攻击的可能性就直线上升。如果没有iftop用sar看历史流量也很实用# 每隔1秒采样一次网络流量共采样5次 sar -n DEV 1 5sar的输出里有rxkB/s和txkB/s通过与日常基线对比就能快速判断带宽是否异常。我这边日常流量平时只有几十MB某次半夜直接冲到900MB以上基本不用等后续命令就知道带宽被打满了。2.2 第二板斧ss与netstat从连接状态里读信号流量只是第一道判断确认攻击的关键还得看TCP连接状态。netstat是传统命令但现在的Linux发行版大多推荐ss在连接数大时更快、开销更小。# 查看当前所有TCP连接及状态统计 ss -ant # 按状态统计连接数量 ss -ant | awk {print $1} | sort | uniq -c | sort -rn正常服务器的TCP连接状态分布大致是大量ESTABLISHED少量TIME_WAIT和LISTENSYN_RECV几乎为0。如果看到SYN_RECV数量持续几百上千甚至上万基本可以确定是SYN Flood。同理如果TIME_WAIT异常高说明短连接建立后关闭得特别频繁常见于端口扫描或某些UDP/连接攻击之后。还要注意看ss -lnt里的Recv-Q和Send-Qss -lnt如果某个监听端口的Recv-Q一直不为0或持续增长说明这个端口的accept队列已经满了大量连接在内核态堆积业务层根本来不及处理。这也是被连接型攻击打爆的典型症状。2.3 第三板斧tcpdump抓包看看报文长什么样到这一步如果连接状态有异常就应该上tcpdump抓包看看实际报文了。抓包是最直观、也最不容易误判的一步。# 抓取网卡上的TCP SYN报文不解析域名显示数字地址 tcpdump -i eth0 -nn tcp[tcpflags] tcp-syn ! 0 -c 100执行之后观察输出的源IP分布。如果100个SYN报文来自100个不同的IP而且这些IP的分布很散、几乎没有重复那基本可以认定是分布式攻击。如果SYN报文的源IP存在大量伪造比如明显不合理的保留地址段说明攻击者连握手都不打算完成就单纯为了占满半连接队列。如果怀疑UDP Flood可以用下面的命令抓UDP包tcpdump -i eth0 -nn udp -c 100正常业务如果不开DNS、NTP等UDP服务UDP流量应该非常少。如果抓到大量不明来源的UDP包可能来自固定某个IP或某个端口说明有人在定向灌流量。抓包这一步不需要抓太久上百个包足够看出规律了。重点看两个信息报文源IP是否分散、报文内容是否有业务特征。3. 深入定位判断攻击类型与攻击源3.1 SYN Flood、UDP Flood、ICMP Flood、HTTP Flood的日志与特征辨别判断攻击类型本质就是看“哪一层的数据异常”。结合第2章的检测结果你可以把现象对号入座。先说SYN Flood。它的核心异常点在ss -ant里的SYN_RECV数量同时内核日志里可能有半连接队列溢出的记录# 查看内核日志过滤TCP相关 dmesg -T | grep -i tcp | tail -20 # 更直接一点看协议栈统计 netstat -s | grep -i SYNs to LISTEN如果SYNs to LISTEN后面的数字巨大且持续增长说明大量SYN报文发到了监听端口但从未完成握手。这就是SYN Flood的最直接证据。UDP Flood的特征则更多体现在带宽上。用iftop看流量大头是UDP协议用tcpdump抓包能看到大量相似大小、相同端口的UDP报文且源IP分布广。如果你的业务本身不对外提供UDP服务那出现海量UDP包基本就是攻击。ICMP Flood相对好认。服务器会突然收到大量ping请求用下面的命令看ICMP收包情况# 查看ICMP报文统计 netstat -s | grep -i icmp或者tcpdump -i eth0 icmp直接看。正常服务器对外不响应ping时收到的ICMP包也很少。如果ICMP包数量暴涨且来自不同源IP多半是ICMP Flood。不过这类攻击现在比较少了因为带宽消耗效率不如UDP/SYN但小流量打过来也可能造成丢包。HTTP FloodCC攻击是最难判断的一类因为报文看起来完全合法。判断依据主要靠应用层日志和连接特征。比如nginx日志里突然出现大量同一个URI的请求、同一个User-Agent的请求、或者大量请求都集中在某个API上# nginx访问日志按IP统计请求次数取前10 awk {print $1} /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10如果某个IP或某些IP的请求量占了总请求量的大半而且这些请求的UA明显不对比如全是Python脚本、curl就需要进一步封禁。3.2 从连接表里揪出攻击源IP找到攻击源IP是应急处理的前提。不管攻击者是不是伪造源IP你总能在连接表里看到“当前正在通信的对端IP”。虽然源IP可能是假的但很多攻击为了维持连接如HTTP Flood必须使用真实IP这就给封禁提供了机会。统计每个源IP与本地IP的连接数# 统计每个源IP的TCP连接数取前20 ss -ant | awk $1 ESTABLISHED {print $5} | cut -d: -f1 | sort | uniq -c | sort -rn | head -20这里解释一下ss -ant第五列是“对端地址:端口”用cut -d: -f1取IP部分然后排序、去重、计数。如果结果是几十个IP各带着几百上千条连接那就再明显不过了。对于SYN_RECV状态同样可以统计源IPss -ant | awk $1 SYN-RECV {print $5} | cut -d: -f1 | sort | uniq -c | sort -rn | head -20注意SYN Flood的源IP很可能是伪造的所以即使统计出来一个“头号攻击IP”直接封禁未必有效——攻击者根本不在乎这个IP能否收到回包。此时更有效的手段是启用tcp_syncookies后面会讲。3.3 看内核与系统日志有没有其他的被动线索除了主动抓包和连接统计系统日志里也会留下攻击痕迹。虽然很多DDoS攻击不上应用层但流量异常、连接堆积会间接反映到内核日志和系统报告中。值得看的日志主要有这几个/var/log/messages或/var/log/syslog内核和系统服务日志/var/log/auth.log认证日志用于排除暴力破解虽然不是DDoS但出现频率高应用日志如nginx的access.log、error.log举一个我踩过的例子某次业务卡顿ss里看到大量连接都是ESTABLISHED且集中在80端口但CPU并不高。直觉告诉我这不像传统DDoS。后来打开nginx error log发现报的是worker_connections are not enough原来是活动连接数涨到了几万而nginx配置里的worker_connections才1024。这不是攻击是一个连接耗尽型故障。所以应用日志是判断“连接层异常”还是“应用层耗尽”的分水岭。还有一种被动线索来自系统层面的“副作用”。比如系统日志里出现大段的超时重传记录# 查看TCP重传统计 netstat -s | grep -i retrans如果重传率异常高说明网络链路丢包严重要么是带宽被打满要么是链路本身有问题。这个数据可以和iftop的入口流量交叉验证入口流量远低于带宽但重传很高那可能是出方向被打了即回包被打常见于反射型攻击。4. 实战排查常见误判与解惑实录4.1 流量高不一定是攻击正常大促、爬虫、数据同步的差异我见过太多“流量一高就喊被攻击”的案例。先说结论流量高本身不是攻击证据必须结合“时间线、来源分布、报文特征”来判断。举三个真实场景。场景一电商大促。某次活动页面流量比平时翻了10倍iftop显示的连接非常多但细看源IP大多来自国内运营商IP段且请求的URL分布很均匀都在访问不同商品页时间曲线呈缓慢爬坡再平稳回落。这种情况就是正常流量高峰。场景二恶意爬虫。某个IP段持续请求同一个接口请求频率看起来像攻击——每秒几百次。但tcpdump抓包显示UA串是某个搜索引擎的爬虫而且来源IP是几组固定的地址段。这属于爬虫问题需要robots协议和nginx层限制跟DDoS是两码事。场景三数据同步/备份。内部系统每天凌晨跑全量备份走的是另一个网卡或专线结果监控只看主网卡看出一大坨流量。这种情况只需要在监控里把备份流量单独分流或者在时间线上直接打标不用大动干戈。区分方法总结就一句话流量高峰是否有明确业务背景、来源IP是否分布广泛、报文是否符合业务特征。三者都异常才算攻击。4.2 TCP连接数暴涨但业务正常先看这几个地方有时候连接数异常高但业务响应“还行”这种状态最容易让人拿不定主意。我排查这类问题时一般按下面顺序检查。先查是不是短连接没有正常关闭。用ss -ant | grep CLOSE_WAIT看是否有大量CLOSE_WAIT。CLOSE_WAIT多意味着服务端被动关闭连接后应用层没有正确调用close()释放连接。这通常是代码问题而非攻击。再查是不是代理或中间层带来的连接堆积。如果你的架构是nginx → tomcat 或 ingress → service那连接可能只是正常堆积在某个环节。用ss -tnp定位进程确认连接都被哪个进程占着如果是Java进程八成是线程池满了在排队。最后检查是不是NAT或负载均衡器的问题。源IP经过NAT后内网客户端可能都显示成同一个IP此时按IP统计连接数会看到“一个IP几万条连接”但其实是几百个用户共享出口IP。看ss -ant里的对端端口如果端口分布是连续的且数量大多数是NAT导致不用紧张。4.3 常见问题FAQ速查表我把日常交流中经常被问到的问题整理成一张速查表方便排查时对照。现象可能原因排查命令处理方向带宽被打满CPU不高流量型攻击UDP/ICMP Floodiftop, tcpdump封禁攻击IP上高防带宽端口通但业务连不上SYN_RECV暴涨SYN Floodss -ant, netstat -s开启syncookies调大半连接队列CPU打满连接数正常请求集中HTTP Flood/CC攻击top, nginx access log应用层限流封禁异常UA/IPCLOSE_WAIT大量堆积代码未释放连接ss -ant修应用关闭连接大量TIME_WAIT短连接频繁ss -ant开启连接复用tcp_tw_reuse出方向流量异常大服务器被作为反射源或已中马iftop, tcpdump排查失陷隔离主机这张表没法覆盖所有情况但能覆盖绝大多数“疑似DDoS”的日常判断。遇到表上没写的情况随时回到第2章的集中检查流程重新过一遍。5. 确认攻击之后的应急处理与临时缓解5.1 先止损快速封禁IP与限流确认是DDoS攻击后应急处理的第一原则是止损而不是“研究清楚再说”。攻击每多持续一秒业务损失都在扩大。最常见的止损操作是封禁攻击源IP。如果第3章已经统计出了明显的攻击IP列表直接封# 封禁单个IP iptables -I INPUT -s 1.2.3.4 -j DROP # 封禁一个IP段 iptables -I INPUT -s 1.2.3.0/24 -j DROP # 查看已封禁规则 iptables -L INPUT -n --line-numbers # 紧急解除封禁注意是-D不是-I iptables -D INPUT -s 1.2.3.4 -j DROP对于伪造源IP的攻击封IP没用因为IP本来就是假的。这时候要启用tcp_syncookies让内核在半连接队列满的情况下通过SYN Cookie机制继续处理请求sysctl -w net.ipv4.tcp_syncookies1 sysctl -w net.ipv4.tcp_max_syn_backlog8192 sysctl -w net.core.somaxconn8192这三个参数只是临时缓解手段真正的根治还靠防火墙策略或高防。但应急时足够撑一阵。如果需要按流量限速可以用tc命令做网卡限速不过在单机层面做限速效果有限更有效的还是在上游路由器或云安全组里配置。5.2 内核参数与DDoS缓解的常用临时手段除sycookies外还有几个调优参数值得记住它们能缓解特定场景下的攻击影响。针对TIME_WAIT过多、连接无法快速回收的问题sysctl -w net.ipv4.tcp_tw_reuse1 sysctl -w net.ipv4.tcp_fin_timeout15tcp_tw_reuse允许内核复用TIME_WAIT状态的连接对大量短连接场景有明显帮助。tcp_fin_timeout缩短TIME_WAIT等待时间让端口更快释放。针对高并发连接适当调大文件描述符限制ulimit -n 65535还有针对SYN Flood的半连接队列上限、SYN重试次数等参数都可以临时放宽sysctl -w net.ipv4.tcp_syn_retries1 sysctl -w net.ipv4.tcp_synack_retries1降低重试次数能让内核更快放弃无效半连接避免队列被长期占用。不过这类参数会影响弱网环境下的正常连接稳定性生产环境调整前务必评估业务场景。所有临时参数要持久化写入/etc/sysctl.conf否则重启后失效。但我不建议在攻击时马上改配置文件——先把参数通过sysctl改上确认有效后再落盘这样能避免“改错配置文件导致重启后网络起不来”的二次事故。5.3 事后复盘与日常监控建议很多团队处理完攻击就收工了这是不对的。攻击结束后一定要做复盘至少回答三个问题攻击入口是什么监控为什么没有提前告警后续如何缩短发现时间关于监控建议日常就应该配好这几项。带宽监控按照网卡维度采集入向/出向流量设置环比突增告警。TCP连接监控采集各状态连接数尤其SYN_RECV、ESTABLISHED、TIME_WAIT设置阈值告警。应用性能监控记录nginx/Java等应用的QPS、响应时间、错误率异常时联动告警。安全设备联动如果条件允许把服务器日志接入IDS/IPS或SIEM平台让系统自动分析异常流量。这些监控不是一蹴而就的但每做一项下次遇到攻击时就能少慌乱几分钟。实际经历过一次完整的DDoS应急之后你就会明白检测手段的价值不在“知道被打了”而在于“尽早知道、知道怎么打、知道该干嘛”。关于DDoS检测与应急我在实际运维中还有一个体会判断要快但手要稳。快是指在几分钟内通过流量、连接、抓包完成判断稳是指不要一看到异常就手忙脚乱地封IP、重启服务而是先对照时间线确认业务变更情况再决定操作。毕竟误封一个正常用户IP段的代价可能比攻击本身更大。最后再分享一个小技巧平时养成记录业务流量基线的习惯不管是高峰期还是低谷期心里有基线数据出了异常才能一眼看出来“这流量不正常”而不是靠猜。
返回列表