1. 先搞清楚TCP协议里到底哪个环节会被Flood我当年刚接触网络安全时一直有个误区以为Flood攻击就是把带宽打满、让服务器网络瘫痪就算完事。真正深入报文层面之后才意识到TCP Flood攻击最狠的地方不是“量大”而是“精准打击协议状态机”——它打的是TCP连接建立和维护过程中的信任机制。理解了这一点后面所有防御手段的取舍逻辑才能看得明白。TCP作为面向连接的可靠传输协议靠三次握手建立连接、四次挥手释放连接连接建立之后依靠序号Sequence Number简称Seq、确认号Ack Number、窗口大小Window Size等字段维护传输状态。整个协议设计建立在“对方会按规则响应”的假设之上攻击者正是利用这一点通过伪造或操纵报文中的这些关键字段诱导服务器分配资源、维持状态最终把服务器资源耗尽。在处理Flood攻击之前有四个TCP报文字段必须像记自己手机号一样记清楚字段作用攻击中被操纵的方式SYN标志位请求建立连接伪造源IP大量发送SYN不回应SYN-ACKACK标志位确认收到数据伪造不存在的连接发送ACK触发查询消耗FIN/RST标志位终止连接利用RST伪造断开干扰正常连接Seq/Ack序号数据排序与确认制造序号混乱导致校验和重传开销配合这些字段TCP头部还有源端口、目的端口、窗口大小等参数。攻击者不会盲目发包每个字节都有目的。我在实际抓包分析时最常看到的攻击报文长度集中在60字节到120字节之间——刚好是TCP头部40字节不含选项就是20字节加上IP头部20字节再算上以太网帧头的最小填充。所以“小包洪流”这个词在TCP Flood里不是形容词是字面意思。需要先明确一个边界TCP Flood攻击通常分为几类包括SYN Flood、ACK Flood、SYN-ACK Flood、RST Flood、FIN Flood等。不同变种的攻击原理差异很大防御思路也完全不一样。有些防御方案对SYN Flood有效但一遇到ACK Flood就失效因为两者消耗的资源对象完全不同。这也是很多新手配置防护策略后依然被打挂的根本原因——没有对症下药。那TCP协议链路层报文解析是什么简单说就是从网卡抓到的原始数据帧开始剥离以太网帧头解析IP头再解析TCP头最终还原出完整的TCP连接上下文。在做Flood攻击分析时不能只看单个报文要看报文之间的状态转换是否符合TCP状态机预期。比如一个源IP如果只发SYN从不发ACK那就是典型的扫描或者攻击特征。如果对端回复SYN-ACK之后源IP立刻回RST那可能是端口探测。如果回ACK但Seq号完全对不上那可能是ACK Flood。这些结论不是靠猜而是靠对报文字段的逐层拆解。2. 常见的几类TCP Flood攻击及各自的消耗逻辑2.1 SYN Flood经典的半连接耗尽攻击SYN Flood的原理用大白话说攻击者不断给服务器发“我要建连接”的请求SYN报文但服务器回复“好的我等你确认”SYN-ACK之后攻击者永远不回复最后那一下确认ACK。服务器得为每一个半开连接维护一个控制块TCBTransmission Control Block这个控制块要占内存连接还有超时时间通常是30秒到2分钟。打个比方你开了一家餐厅有人不停打电话订位你记下他的电话号码和订餐需求但对方从来不来。漫长的等待时间里你手头的便签纸一张张被浪费掉等到便签纸用完真正的客人订不了位了。TCB池就是餐厅的便签纸。关键参数Linux系统里半连接队列的大小由net.ipv4.tcp_max_syn_backlog控制默认值通常是1024或者更大一点。当半连接队列被打满之后服务器对新来的SYN请求直接丢弃。攻击规模不需要太夸张就能触发这个阈值——如果攻击源IP数量多、五元组各不相同很容易就把队列塞满。我在实际环境中见过一个现象正常情况下服务响应延迟在10ms以内SYN Flood打起来之后新连接建连失败、延迟飙升到数秒甚至直接超时。但已经建立的连接反而还能正常工作——因为攻击消耗的是半连接队列不是全连接队列。所以如果监控里只盯“已建立连接数”很可能错过SYN Flood的早期信号正确的监控维度是“半连接数SYN_RECV状态数量”和“每秒SYN接收量”。2.2 ACK Flood让服务器做无谓的状态查询ACK Flood的巧妙之处在于攻击者发送的是ACK报文确认报文这些报文指向的所谓“连接”在服务器上根本不存在。服务器收到一个ACK需要查询这个连接是否存在——如果存在就更新状态、处理数据如果不存在就直接丢弃。问题出在“查询”这个动作上。Linux内核收到TCP报文后要通过哈希查找对应的socket。当攻击者构造大量五元组完全不同的ACK报文时每个报文都需要内核从头到尾执行一次查找流程包括计算哈希、遍历冲突链。这个操作的CPU开销远大于单纯的收包丢包。用四核机器实测攻击流量一旦上到每秒几十万PPSCPU的softirq软中断占比会快速飙到100%整机吞吐断崖式下跌。防御ACK Flood最直接的手段是在网络入口处直接丢弃不合理的ACK报文。怎么判断不合理核心是来源判断服务器从未向某个源IP发送过SYN-ACK那这个源IP发来的ACK就必然是伪造的直接丢。高级一点可以采用“TCP Cookie”技术——服务器发出的SYN-ACK里带上一个基于四元组和密钥计算的Cookie序号完全随机攻击者无法预先猜出合法连接的Seq范围后续ACK必须回带正确的确认号否则直接丢弃。2.3 SYN-ACK Flood与RST Flood反射与欺骗的变种SYN-ACK Flood通常是反射攻击的一环攻击者伪造受害者IP作为源地址向大量互联网上的服务器发送SYN请求这些服务器回应的SYN-ACK全部流向受害者。受害者收到海量自己从未发出过SYN的SYN-ACK报文内核每处理一个都要做查找匹配失败后回RST一来一回消耗双向带宽和CPU。这种攻击防不住的是源头——你没法控制别人的服务器不回包所以防御主要靠流量清洗和限速。RST Flood则更阴险。攻击者伪装成通信一方向另一方发送RST重置连接报文。如果Seq号恰好落在对方当前接收窗口内连接会被立即切断。这类攻击在游戏服务器上尤其常见玩家正在打Boss突然掉线就是典型的RST攻击效果。防御办法开启net.ipv4.tcp_challenge_ack_limit保护、使用TCP Authentication OptionTCP MD5签名RFC 2385或TCP-AO确保报文无法被伪造。攻击类型消耗对象核心防御思路常见误判SYN Flood半连接队列/内存SYN Cookie、半连接队列调优以为加带宽就能解决ACK FloodCPU/软中断无状态丢弃、Cookie校验以为是正常流量突增SYN-ACK Flood带宽/CPU流量清洗、BGP牵引误判为被DDoS大流量攻击RST Flood业务连续性报文校验、MD5签名以为是网络波动或客户端问题3. 从抓包到定性一次完整攻击分析和排查链路很多朋友习惯一收到告警就直接封IP、拉黑名单但我建议先花几分钟做一次完整分析搞清楚攻击类型和特征再决定防御动作。误封正常用户IP的例子我见得太多了——封完攻击没了业务也崩了最后还是得灰溜溜解封。3.1 第一步确认异常特征先判断是不是Flood攻击标准动作是看三个维度的指标网络层PPS每秒包数是否飙升而带宽占用可能不高。TCP Flood多数是小包攻击带宽可能只有几百Mbps但PPS却达到百万级别。传输层SYN_RECV状态连接数、TIME_WAIT连接数、当前总连接数是否存在异常。应用层新建连接成功率、连接建立耗时、错误日志中的超时记录。我常用的命令组合# 查看当前TCP连接状态统计 ss -ant | awk {print $1} | sort | uniq -c | sort -rn # 查看每秒新建SYN请求的大致速率每秒执行一次 watch -n 1 netstat -s | grep -i syn # 抓包查看握手完成率 tcpdump -i eth0 tcp[tcpflags] (tcp-syn|tcp-ack) ! 0 -nn -c 1000如果发现SYN_RECV数量从正常几十涨到几万或者netstat -s里SYNs to LISTEN sockets dropped数值持续增长基本可以判定是SYN Flood。如果是CPU的softirq直接打满、网卡收包中断频繁触发而连接状态看起来还算正常则更可能是ACK Flood或纯PPS攻击。3.2 第二步抓包分析报文特征抓包是定位攻击类型的黄金标准。我通常会在入口交换机做端口镜像或者直接在服务器上跑tcpdump按以下过滤条件抓取可疑流量# 只抓syn包统计源IP分布 tcpdump -i eth0 tcp[13] 2 ! 0 -nn -c 5000 -w syn.pcap # 只抓ack包且没有syn标志 tcpdump -i eth0 tcp[13] 18 16 -nn -c 5000 -w ack.pcap抓完用Wireshark打开优先看三件事第一源IP分布是否均匀。如果几百万个报文只来自几十个IP那是少量肉鸡在打可以按IP封禁或限速。如果源IP极其分散每个IP的报文量都不大——几百上千个包——那攻击者可能用了真实分布式的僵尸网络单封IP意义不大。第二TTL值是否异常一致。很多伪造报文的工具默认TTL值固定在64或128如果大量报文的TTL高度一致大概率是伪造流量。真实互联网用户经过不同路由TTL通常会有波动。第三序列号是否随机。有些攻击工具生成的Seq号是固定值或等差递增而正常TCP连接的Seq号通常是随机的。发现大量报文Seq号集中在某个区间说明是工具构造的包。3.3 第三步验证连接时序这里分享一个小技巧只看单个报文容易误判把同一五元组的报文按时间排序就能还原整个“伪连接”的过程。例如只看到SYN → SYN-ACK然后没有ACK——半连接攻击只看到SYN → SYN-ACK → RST——可能是扫描或异常客户端只看到ACK没看到之前的SYN——伪造连接ACK Flood先SYN → SYN-ACK → ACK建连后立刻RST——有可能是攻击者发送RST消耗服务器也可能是正常客户端快速关闭用Wireshark的“Follow TCP Stream”功能可以快速查看某个五元组的所有报文时序。如果大量流都呈现“建连后立即RST”的模式基本可以断定是RST Flood。4. 防御实战从内核参数到流量清洗的分层策略4.1 内核参数层的首道防线Linux内核的参数调优是防御TCP Flood的第一道门槛成本最低、见效最快。但不同攻击类型对应的参数完全不同别一把梭全改。针对SYN Flood最核心的开关是SYN Cookie# 开启SYN Cookie不分配半连接队列条目改为用cookie编码连接信息 sysctl -w net.ipv4.tcp_syncookies1 # 半连接队列最大值调大给正常业务更大的缓冲 sysctl -w net.ipv4.tcp_max_syn_backlog8192 # 调大全连接队列 sysctl -w net.core.somaxconn8192 # 减少SYN-ACK重传次数加快无效半连接回收 sysctl -w net.ipv4.tcp_synack_retries2SYN Cookie的原理当半连接队列满时服务器不再保存连接状态而是把连接信息加密编码到SYN-ACK的Seq号里等客户端回复ACK时再解码验证。这个办法能完美扛住“半连接队列被打满”的问题CPU开销也不大。代价是牺牲了一些TCP扩展特性如大窗口、SACK但对绝大多数业务来说攻击时保命比性能重要。针对ACK Flood内核参数能做的事情有限因为主要开销在内核查找socket的流程。可以做的优化是# 启用tcp_tw_reuse和tcp_tw_recycle注意新内核已移除tcp_tw_recycle sysctl -w net.ipv4.tcp_tw_reuse1 # 调整local_port_range保证正常连接有充足端口可用 sysctl -w net.ipv4.ip_local_port_range1024 65535注意tcp_tw_recycle在NAT环境下会引发严重的问题因为NAT后面的多个客户端共享同一个公网IP时间戳不同会导致合法连接被丢弃。这个坑我踩过不建议开启。4.2 iptables/nftables与无状态防御iptables的connlimit模块可以限制单个源IP的并发连接数对抵御小规模SYN Flood有效# 限制单个源IP最多500个并发连接 iptables -A INPUT -p tcp --syn -m connlimit --connlimit-above 500 -j DROPhashlimit模块可以做速率限制# 每个源IP每秒最多10个SYN包超过即丢 iptables -A INPUT -p tcp --syn -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name syn_limit -j DROP但说实话iptables类的软件防火墙在百万级PPS攻击面前性能完全不够看。因为每个包都要经过内核协议栈层层匹配规则大量CPU时间都耗在netfilter框架里。实际大流量攻击下还是得靠硬件防火墙或云清洗iptables更适用于中小规模攻击的自动缓解。我见过的一种有效组合在边界路由器上用ACL直接丢弃伪造源IP的包如源IP是内网地址、源IP是广播地址然后在防火墙上用连接状态规则做精确放行“只允许状态为ESTABLISHED和RELATED的流量通过对NEW状态的连接做限速”。这样即使攻击包进了边界也无法进入服务器内核协议栈深处。配置示例# 只允许合法新连接进入放行已建立连接 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -m state --state NEW -p tcp --dport 443 -m connlimit --connlimit-above 1000 -j DROP iptables -A INPUT -m state --state INVALID -j DROP这里有个重要细节INVALID状态的包必须丢。很多攻击报文——比如乱序的ACK、窗口外的SEQ——会被内核标记为INVALID如果不提前丢它们还会继续到应用层造成干扰。4.3 SYN Proxy与流量清洗真正扛住大流量的方案如果攻击流量超过单机处理能力——比如PPS超过500k单靠服务器自身防御已不现实。这时候必须把防御前置SYN Proxy模式防火墙代替服务器完成三次握手验证通过后再与服务器建立连接。这样攻击者的SYN在防火墙这一层就被终结服务器看到的全部是经过验证的真实连接。实现路径硬件防火墙如各类国产/商业防火墙、Linux下的synproxy模块nftables直接支持、或者负载均衡器的TCP代理模式。BGP牵引与流量清洗把被攻击IP的流量通过BGP路由通告牵引到清洗设备清洗设备剥离攻击流量后将干净流量通过隧道回注到源站。这是目前对抗大流量TCP Flood的主流方案阿里云、腾讯云的高防IP都是这个架构。清洗设备判断攻击包的核心逻辑很简单——它跟真实客户端完成了代理握手没有完成的握手就不算真实连接。我的实测经验是SYN Proxy防御SYN Flood极有效攻击量在200万PPS以内、全部是SYN包时后端服务器几乎无感。代价是TCP连接时延增加约一个RTT对游戏、高频交易这类对延迟敏感的业务需要评估这个损失是否可接受。4.4 应用层与业务侧兜底即便有了所谓“全网防御”应用层仍然要做兜底设计。我始终认为防御不是靠单点而是靠纵深。常见做法连接白名单对可信IP、内部系统、合作伙伴IP放入白名单直接绕过攻击检测。业务层快速失败对明显异常的连接比如握手完成后立即发送大量无效数据快速断开不占线程池资源。线程池与连接池隔离把接受连接accept的逻辑和处理业务的逻辑分离避免攻击造成全局线程阻塞。监控告警先行对SYN_RECV、TIME_WAIT、PPS、新建连接数四个指标设置告警阈值。提前告警永远是低成本防御的前提。5. 一次游戏服务器RST Flood的真实排查过程光讲理论不够分享一次实际案例。有次接到一个游戏客户反馈玩家频繁掉线但服务器CPU、带宽、连接数全都在正常范围。如果只盯着服务器自身指标这个问题极难排查——因为RST Flood的攻击流量可能根本没有进入服务器而是直接打在了客户端与服务器之间的链路上。排查链路是这样的第一步在服务器上抓包发现TCP连接异常断开前没有收到任何来自客户端的FIN或RST说明断开请求不是来自对端。服务器自己也没有发出RST但连接却断了——说明断开动作发生在客户端和服务器之间的某个中间节点上。第二步在客户端本地同时抓包。两边对比后发现服务器还在正常发送数据客户端的网络栈却已经发出了RST并关闭了socket。这个RST是客户端主动发出的为什么因为客户端收到了一个“看起来来自服务器”、但Seq号落在接收窗口之外的伪造RST报文客户端认为连接异常主动断开。第三步分析伪造RST的特征。抓包发现伪造RST的TTL是52而真实服务器到客户端的TTL是53差了1跳。攻击者应该是控制了一个靠近客户端链路的节点注入伪造报文TTL差异暴露了攻击来源。最终通过调整客户端路由、在ISP侧封堵攻击源、配合在服务器侧开启TCP MD5签名解决了问题。这个案例说明了三点TCP Flood不是只有“大流量”一种形态精准的小流量攻击更难防。排查攻击必须有端到端视角不能只看服务器单点。防御RST Flood最有效的手段还是协议级认证——TCP MD5签名或者TCP-AO虽然配置成本高但能从根上切断伪造报文。6. 深度观察为什么防御TCP Flood比看上去更难TCP Flood难防御的根源不在技术方案本身而在协议的开放设计。TCP协议诞生于一个信任的网络环境它的校验机制、超时重传机制、状态管理机制在设计时都没有考虑恶意参与者。攻击者不需要“攻破”任何漏洞只需要“滥用”协议规则就能达到目的。这就决定了防御方处于天然劣势——你要为所有合法流量负责攻击者只需要制造异常。另一个难点是攻击流量很难与正常流量区分。比如ACK Flood在实际业务中客户端丢失了SYN-ACK后重新发送ACK也是合法行为。攻击者只要模拟这种“合法异常”检测系统就很容易误判。这也是为什么目前主流方案不是“识别攻击”而是“验证来源”——用代理握手、Cookie、密码学签名等方式让合法流量和伪造流量在入口处就被区分开。从防御演进趋势看未来TCP Flood防御会越来越多地依赖以下几种手段状态化代理的规模化部署——把验证逻辑从应用服务器前置到网络边缘。加密与认证的普及化——TCP-AO替换MD5连接认证成本进一步降低。机器学习的流量基线建模——根据业务的长期流量特征自动识别偏离基线的流量并下发策略。云原生环境下的分布式清洗——容器化和Service Mesh环境下防御节点更靠近业务实例。但这些手段背后都有一个共同的思路不要让服务器自己去分辨善恶让协议验证机制和前置节点完成筛选把最干净的流量交给业务。根据我个人经验如果要做一次从零开始的TCP Flood防御体系建设优先级排序应该是先做监控告警看清楚是否被打再开SYN Cookie等内核防护花小钱防小打然后配置状态防火墙/软件限速防中量攻击最后接入云清洗或硬件防火墙防大打。顺序反了容易花冤枉钱还起不到效果。这里再补个小技巧防御策略配置完后一定要做“攻防演练”用工具模拟各类攻击流量验证策略是否生效。hping3是测试SYN Flood常用的工具2-3万PPS就能验证出基础防护是否有效# 模拟SYN Flood攻击测试 hping3 -S -p 80 --flood --rand-source 目标IP # 模拟ACK Flood攻击测试 hping3 -A -p 80 --flood --rand-source 目标IP演练时注意别在正式生产环境打否则误伤线上业务。先用测试机验证策略再逐步上生产。这个钱和时间不能省——因为只有真正挨过打才知道自己的防护体系缺哪块。
