从SYN Flood到ACK Flood:TCP协议栈DDoS攻击防护实战

发布时间:2026/9/16 3:29:00
从SYN Flood到ACK Flood:TCP协议栈DDoS攻击防护实战 凌晨处理过告警的同学都懂那种感受监控大屏上eth0入口流量突然拉满CPU的softirq直接飙到90%ssh登上去敲个命令都卡。我印象最深的一次netstat -ant | grep SYN_RECV | wc -l出来是六位数半连接队列被塞得死死的任何一个正常访客都进不来。那时候以为SYN Flood就是洪水攻击的全部后来被SYN-ACK Flood和ACK Flood轮番教做人才意识到TCP协议栈的攻击面远不止一种打法。这篇文章把TCP视角下的DDoS攻击防护梳理一遍重点是Syn_Ack、Ack_Flood这类与TCP握手状态强相关的攻击手法以及从内核参数、防火墙规则到清洗设备的分层防御思路。无论你是被打了才来临时抱佛脚还是提前加固想少踩坑都可以直接对照着操作。1. 先搞懂TCP三次握手所有洪水攻击都从这里开始1.1 握手状态机决定了攻击面TCP三次握手的流程人人都背得出来客户端发SYN服务端回SYN-ACK客户端再回ACK然后进入ESTABLISHED状态。但防护DDoS不能只背流程要清楚每个阶段在内核里对应什么状态。服务端视角下收到SYN后连接进入SYN_RCVD这一状态下的连接被放入半连接队列收到ACK后连接变为ESTABLISHED然后被移入全连接队列等待应用程序调用accept()取走。这两条队列就是洪水攻击的主战场。SYN Flood打半连接队列ACK Flood打全连接队列和处理路径SYN-ACK Flood则直接冲击内核协议栈对无状态包的处理能力。很多人看攻击只盯着“包量大不大”其实判断攻击类型的关键是看连接状态分布如果SYN_RCVD数量异常高大概率是SYN Flood如果TIME_WAIT和ESTABLISHED同时异常可能是连接耗尽型攻击如果系统CPU被打满但连接表正常那就要考虑是不是大量无效ACK小包。1.2 半连接队列、全连接队列与syncookies的纠葛半连接队列的容量由net.ipv4.tcp_max_syn_backlog和net.core.somaxconn共同约束全连接队列则由net.core.somaxconn和应用程序listen时的backlog参数共同决定。这个细节非常容易踩坑有些文章只让你调somaxconn结果tcp_max_syn_backlog没动半连接队列依然很小SYN包一多照样丢。syncookies是Linux内置的第一道防线。半连接队列满后内核不存储SYN连接信息而是通过计算一个cookie放入SYN-ACK的序列号中返回给客户端客户端回ACK时带上这个cookie内核再重建连接信息。它能把半连接队列溢出的问题绕过去但代价是丢弃部分TCP扩展选项比如大窗口、时间戳、SACK等。这也解释了为什么在高带宽高延迟链路上开启syncookies后某些客户端的传输性能会下降。另一个重要的点是全连接队列溢出时tcp_abort_on_overflow参数决定内核行为。设为1会直接回RST断开新连接设为0则静默丢包。生产环境我建议保持0因为RST会让客户端立刻感知失败并可能引发大量重连静默丢弃反而让客户端等待重传给业务争取一点缓冲时间。2. 四类TCP洪水攻击的原理拆解从SYN Flood到混合变种2.1 SYN Flood把半连接队列写满SYN Flood的思路非常直接伪造大量不可达的源IP向目标发送SYN包。服务器收到后进入SYN_RCVD按规则回复SYN-ACK然后等待客户端的ACK。因为源IP是伪造的客户端永远不会回ACK连接就一直挂在半连接队列里直到超时被内核回收。攻击者只需要持续发送SYN包让队列积压速度大于超时回收速度队列就会被填满正常用户的SYN请求全部被丢弃。判断SYN Flood有一个很实用的特征源IP分布几乎全是乱序的、高位端口随机而且同一个源IP出现次数极少。因为攻击者要伪造源IP通常会随机生成不会用同一个IP反复打。如果你看到某几个IP贡献了绝大多数SYN包那可能是扫描器或者定向骚扰不是真正的洪泛。2.2 SYN-ACK Flood反射放大自己干自己SYN-ACK Flood和SYN Flood原理完全不同它利用的是TCP协议栈对SYN包的“义务回复”。攻击者把受害者的IP地址伪造为源IP然后向互联网上大量真实主机发送SYN包这些无辜主机收到SYN后按协议回SYN-ACK包流量最终全部涌向受害者。这类攻击的可怕之处在于分布式叠加效应。攻击者只要控制少量机器发送低速率SYN就能利用公网上成千上万的服务器作为放大器。受害主机看到的现象是自己根本没有发起过连接却收到大量来自陌生IP的SYN-ACK包。内核检查后发现连接表中找不到对应的SYN记录于是回RST包但这个查找和回复过程本身就在消耗CPU包量足够大时协议栈直接被打满。防护上上游路由器的URPF单播反向路径检查和BCP38入口过滤能从源头上抑制伪造源IP的流量这也是运营商层面的标准做法。自建机房只能依赖专业清洗设备对无状态包进行识别和拦截。2.3 ACK Flood无效连接也让你CPU拉满ACK Flood是我见过最阴险的一类。攻击者发送大量ACK包这些包可能对应不存在的连接也可能命中一个已关闭的端口。内核处理每个ACK首先要在连接表中查找匹配项查不到就回RST。不管查得到查不到查找这个动作本身就要消耗CPU资源。更恶心的是很多防火墙和CDN设备默认放行“已建立连接”的返回流量。攻击者如果先构造一个合法的TCP连接然后持续发送ACK包设备会认为这些包属于已建立的会话直接放行到后端服务器绕过了前置过滤。这也解释了为什么有些环境明明加了高防源站还是被打挂了——流量是被清洗了但清洗设备认为合法的那部分ACK依然能穿透到源站。2.4 混合型与状态耗尽型攻击近年来的攻击很少只用单一类型更多的是SYN、ACK、FIN、URG乱序组合的“杂牌军”。这些包要么协议栈处理路径完全随机要么专门针对防火墙的状态表做填充目的是让中间设备在状态匹配上消耗大量内存和CPU。还有一类是慢速连接耗尽攻击不追求带宽峰值而是用慢速率建立大量看似正常的TCP连接然后长期占用连接表、线程和内存。常见手法包括建立连接后不发送任何数据、发送零窗口通告让对端停止发送、用极低速率发HTTP头占住Web服务器连接池。这类攻击绕过了以“速率”为阈值的防护策略需要从应用层设置合理的超时和最大连接数来配合防御。攻击类型主要攻击包关键消耗目标典型异常特征SYN FloodSYN半连接队列SYN_RECV堆积源IP分布离散SYN-ACK FloodSYN-ACKCPU、协议栈收到大量应答包无对应SYN请求ACK FloodACKCPU、连接表小包高PPSCPU中断高混合变种SYNACKFIN/URG协议栈、防火墙状态表包特征混乱状态表膨胀3. 被打了怎么判断观测指标与抓包定位思路3.1 五类关键指标判断攻击不能靠感觉要盯指标。我总结了几个优先看的半连接数量ss -ant state syn-recv | wc -l正常业务服务器个位数到几十都算正常持续在数千以上就要警惕。TCP状态分布netstat -ant | awk {print $NF} | sort | uniq -c | sort -rn看SYN_RECV、TIME_WAIT、CLOSE_WAIT、ESTABLISHED的比例是否偏离基线。包速率PPS通过网卡统计或抓包计算攻击往往是PPS先起来然后才带动带宽上涨。CPU softirq占比top里si字段长期超过30%说明中断处理已经把CPU吃满了。连接表容量ss -s看sockets使用量或者cat /proc/sys/net/netfilter/nf_conntrack_count和nf_conntrack_max的对比。3.2 netstat与抓包判读实战有一次我排查一台Web服务器netstat -ant里SYN_RECV数量稳定在8000左右但因为开了一个高流量活动业务方坚持认为是正常用户涌入。我没争辩直接抓了1000个SYN包看源端口分布tcpdump -i eth0 -nn -c 2000 tcp[13]2 !0 -w /tmp/syn.pcap然后看源IP聚合和源端口分布。正常用户请求的源端口分布在1024到65535之间但会有一定的聚集性而伪造抓包里端口完全随机且源IP几乎每个都不重复。另外观察TCP包的时间戳选项部分伪造包因为操作系统栈不完整时间戳缺失或不符合递增规律。这几个特征一出来攻击的结论就坐实了。还有一个容易误判的点全连接队列溢出也会表现为SYN_RECV堆积。由于tcp_abort_on_overflow设为0时内核会静默丢弃完成握手的连接客户端会重传SYN服务端又收到大量SYN症状看起来像SYN Flood。区分方法是看监听套接字的Recv-Qss -lnt | awk /LISTEN/ {print $2, $3}Recv-Q表示全连接队列中等待accept的连接数如果Recv-Q持续大于Send-Q说明是应用层accept太慢导致的不是典型的SYN Flood。3.3 别把正常突发误判成攻击有一类误告警来自运营活动。某次一个电商平台做秒杀前端入口机单机SYN包速率从每秒几百跳到几万限速规则直接触发把正常用户给挡了。这事提醒我做防护规则前先留好业务基线尤其是历史秒杀、抢票、大促期间的流量模型。如果一个IP因为NAT共享被大量用户使用hashlimit按源IP限速就会把它误杀。互联网上还有大量随机扫描器如某些工控设备探测、漏洞扫描引擎它们也会产生大量SYN连接。它们的特征是源IP固定但目的IP和端口遍历这和洪泛攻击“源IP离散、目的端口固定”正好相反区分时要看具体场景。4. 防护策略分层落地从内核参数到边缘清洗4.1 第一层内核协议栈调优内核参数是成本最低、见效最快的防线但很多人只是把网上的配置抄过来没理解每个参数的作用。我常用的核心配置如下net.ipv4.tcp_syncookies 1 net.ipv4.tcp_syn_retries 1 net.ipv4.tcp_synack_retries 1 net.ipv4.tcp_max_syn_backlog 65535 net.core.somaxconn 65535 net.ipv4.tcp_abort_on_overflow 0 net.ipv4.tcp_fin_timeout 15 net.ipv4.tcp_keepalive_time 600 net.ipv4.tcp_keepalive_intvl 15 net.ipv4.tcp_keepalive_probes 3 net.ipv4.tcp_tw_reuse 1 net.core.netdev_max_backlog 65535 net.netfilter.nf_conntrack_max 655360 net.netfilter.nf_conntrack_tcp_timeout_syn_recv 10 net.netfilter.nf_conntrack_tcp_timeout_syn_sent 10 net.netfilter.nf_conntrack_tcp_timeout_established 1800tcp_synack_retries1的意思是服务端对SYN-ACK只重试一次这能加快半连接队列中无效连接的回收速度。tcp_fin_timeout15缩短了FIN_WAIT_2的等待时间。nf_conntrack系列参数针对连接跟踪模块如果服务器根本没有启用conntrack也不用理会。要特别强调调参不是越大越好。tcp_max_syn_backlog调到几十万如果机器内存只有4G光连接表就把内存吃光了反而更容易被打死。参数要根据机器的实际承载能力和业务模型来定先看free -m再决定。4.2 第二层iptables限速与SYNPROXY内核参数之外iptables的hashlimit模块可以做源IP粒度的SYN限速这是比较轻量的方案modprobe xt_hashlimit iptables -t raw -A PREROUTING -p tcp --dport 80 --syn -m hashlimit \ --hashlimit-above 100/sec --hashlimit-burst 200 \ --hashlimit-mode srcip --hashlimit-name syn-flood \ --hashlimit-htable-size 32768 -j DROP这条规则限制每个源IP每秒最多100个SYN包如果在NAT出口后面用户量大时要相应调高阈值否则会误伤。面对大流量SYN FloodLinux还提供了SYNPROXY内核代理方案。它的思路是代替后端服务器完成三次握手只有握手成功的连接才转发给后端把半连接压力全部扛在代理层。基本配置如下iptables -t raw -A PREROUTING -p tcp --dport 80 --syn -j NOTRACK iptables -A INPUT -p tcp --dport 80 --syn -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate INVALID -j DROP注意NOTRACK规则要先跳过连接跟踪否则SYNPROXY不生效。这套方案能扛住相当可观的SYN包洪泛但它只解决SYN Flood对纯ACK Flood基本无能为力因为ACK包根本不走SYNPROXY的代理路径。所以它是对抗SYN攻击的补充手段不能替代专业清洗设备。4.3 第三层专业清洗设备与CDN高防到了T级流量级别自建机房的Linux服务器已经没法硬扛了这时候要靠上游的流量清洗和黑洞调度。云厂商的高防IP和带清洗能力的CDN是主流选择它们把攻击流量吸引到清洗节点过滤后再把干净流量回源到真实服务器。接入高防后有一个很容易被忽略的点必须限制源站只接受高防回源IP的访问否则攻击者只要拿到源站IP直接绕过高防打源站防护就形同虚设。一般通过防火墙做IP白名单iptables -A INPUT -s 高防回源IP段 -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j DROP另外要关注回源链路本身的带宽和连接数。很多清洗设备把攻击洗掉了但正常流量回源的瞬时连接数仍然可能超过源站处理能力源站侧的内核参数和应用层超时配置必须提前优化好。4.4 应用层联动TCP层的洪水攻击最终都要落到应用层Nginx和Java应用相关的参数也要联动调整。Nginx作为接入层时监听端口的backlog要和内核的somaxconn对齐server { listen 80 default backlog65535; keepalive_timeout 10; }连接超时时间不能设置太长。攻击者建立TCP连接后占着不放如果keepalive_timeout是75秒几千个连接就能把worker连接池耗尽。调短到5到15秒是常见做法但要注意业务是否有长连接需求短连接场景和长连接场景的取舍不同。这也是为什么很多人问TCP长连接和短连接对防护有什么影响——本质上就是连接超时和连接数上限的博弈。5. 实战中踩过的坑调优反噬与误伤问题5.1 syncookies不是万能膏药有次我帮朋友调了一台服务器开了syncookies后SYN_RECV数量确实降下来了但业务反馈客户上传大文件变慢。排查半天发现是syncookies丢弃时间戳选项后TCP窗口缩放失效大文件传输无法使用大窗口相当于在高带宽链路上自废武功。这个问题在跨地域传输时尤其明显。所以syncookies适合作为应急开关不建议长期依赖。正常情况下保持开启没问题但如果业务有大量长肥管道传输要评估开启后对吞吐的影响。5.2 TIME_WAIT参数的前车之鉴有些运维看到TIME_WAIT多了就急着开tcp_tw_recycle这是个深坑。老内核开启tcp_tw_recycle后会收到同一个源IP的连接的HELLO如果该源IP来自NAT出口不同用户的时间戳不同步新连接会被随机丢弃用户表现就是网页打不开、连接超时。内核4.12之后tcp_tw_recycle已经被移除但低版本服务器上依然存在这个问题。tcp_tw_reuse只对客户端出方向生效服务端改它是没用的。我处理TIME_WAIT过多的经验是先看它对系统有没有实际影响。TIME_WAIT本身占用内存不多除非达到几十万级别导致本机端口耗尽服务端接受连接一般不涉及否则不用刻意清理。实在要调优先缩短tcp_fin_timeout而不是碰recycle这种激进参数。5.3 hashlimit误杀与防误杀设定正则限速对单机IP的工作机制有一个天然盲区一旦攻击源分布在大量不同IP上每个IP的速率都不超过阈值hashlimit就废掉了。反过来如果企业出口是一个NAT池几千个员工共用几个公网IPhashlimit会把整个出口IP限死。解决思路是调整限速粒度。hashlimit有很多模式srcip按源IP限srcip,dstip按源目IP对限或者干脆不做源IP限速改为全局速率限制。每种模式对应不同场景没有一劳永逸的方案。我在自建防护时会先抓半小时正常流量统计出源IP速率分布的P99再在这个基础上做一定余量来设定阈值。5.4 源站回源连接瞬间打满高防场景下还有一个容易被忽视的坑攻击流量被清洗之后回源到源站的正常流量爆发式增长。比如某个业务平时CPS每秒新建连接数只有几百被攻击期间用户不断刷新清洗恢复后所有积压的用户同时重连回源CPS瞬间冲到上千甚至更高源站连接表直接打满表现为“攻击停了业务还是恢复不了”。应对办法是给源站配置CPS限流或者在应用层加排队机制。Nginx可以用limit_conn和limit_req做连接和请求速率限制把流量削峰填谷limit_conn_zone $binary_remote_addr zoneconn_limit:10m; limit_conn conn_limit 50;6. 防护效果验证自测压测与复盘习惯防护搭好了不等于一劳永逸要验证有效性而且要定期验证。我经常在隔离环境下用hping3模拟小规模SYN Flood观察防护规则是否按预期生效。强调一下这种测试只能在自有服务器和专用测试环境做生产网络和未授权目标绝对不能乱试。# 以随机源IP发送小规模SYN包到测试机的80端口 hping3 -S -p 80 --flood --rand-source -d 64 192.0.2.10测试时重点观察几个指标ss -ant state syn-recv | wc -l是否保持在可控范围top里si软中断占比是否长期超过30%ss -s中TCP总量的增长速度/proc/net/stat/syncookies中SyncookiesSent和SyncookiesRecv的计数变化。测试结束后的恢复确认同样重要。攻击停止后半连接和全连接队列不会立刻清空要观察一段时间确保状态回落到基线水平。同时查看网卡的丢包和错误计数ethtool -S eth0 | grep -E drop|discard netstat -i如果丢包计数器持续增长说明防护规则已经介入但可能阈值过严或过松需要重新调整。还有一个好习惯是定期保存TCP状态基线。每次业务活动前后把ss -s的输出和sysctl里TCP相关参数存一份快照下次告警来了直接对比。我现在处理故障的第一件事不是看日志是拿历史基线和当前状态做diff往往一眼就能看出异常点。DDoS防护没有终点攻击手法会跟着防御迭代不断变形。今天重点梳理的SYN Flood、SYN-ACK Flood、ACK Flood只是TCP协议栈攻击的基础打法后续还会出现更多利用协议特性做文章的花样。保持对TCP状态机的敏感把内核参数、防火墙规则和清洗设备之间的配合关系理顺才能在打过来的时候不慌。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询