SYN Flood攻击能占满半连接队列,本质是攻击者用伪造IP的SYN包让服务器陷入无休止的等待确认状态,队列一旦耗尽,正常连接请求被直接丢弃,服务自然不可用。 这种攻击不依赖大流量,也不需要攻破系统,只需要抓住TCP握手设计里的一个“等待漏洞”,就能让一台高性能服务器瘫在原地。
SYN Flood攻击原理是什么?半连接队列为何成为软肋
三次握手中的“半途而废”:半连接队列的作用
想象一下服务器是一个前台,TCP连接就是一次拜访,客户端发来SYN包,就像敲了门,前台把访客名字记在“待客名单”上,然后回一句“来了?我马上开门”,同时等待客户再回一句“好,我到了”,这个“待客名单”就是半连接队列,写入名单的连接状态叫SYN_RECEIVED。
正常流程下,客户端收到SYN-ACK后会回复ACK,握手完成,连接从“半成品”变成“成品”,转入全连接队列,但如果只听到敲门声,没有后续回应,这些名字就得一直挂在名单上,直到超时才能清理,半连接队列的容量有限,而攻击者要做的,就是让名单以极快的速度堆满。
攻击者如何用伪造源地址“刷爆”队列
SYN Flood最狠的地方在于,攻击者根本不打算完成握手,它伪造海量来源IP,构造大量SYN包发给服务器,服务器毫无防备,对每个包都回一发SYN-ACK,然后傻等那个永远不会出现的ACK,半连接队列的容量通常是有限的,常见Linux发行版的tcp_max_syn_backlog默认值在128到1024之间,攻击流量动辄每秒几万包,只需要几秒甚至更短,队列就满了。
队列满后,内核处理新SYN包的策略很简单:直接丢,正常用户发来的SYN请求排在队伍尾巴上,结果连进队的机会都没有,表现就是浏览器一直转圈,最终提示连接超时。
网站被SYN Flood攻击表现有哪些?用户和运维视角
从用户角度看,网站像“死”了一样:页面打不开,刷新好几次偶尔出来半张图,然后彻底没了反应,从运维角度看,登录服务器执行netstat -ntu,会看到大量SYN_RECEIVED状态的连接,数量成百上千,而ESTABLISHED却少得可怜。CPU和内存可能还很空闲,但外部就是连不进来,这种“服务器明明活着,却服务不了”的现象,正是半连接队列被占满的典型特征。
半连接队列满了怎么办?从排查到防御的实操路径
快速验证:用命令确认半连接队列溢出
别急着猜,先用证据说话,行业共识认为,判断半连接队列是否溢出有两条快速路径。
- 执行
netstat -s | grep -i "SYNs to LISTEN",如果输出里有“SYNs to LISTEN sockets dropped”且计数非零,说明有SYN包被丢弃,很可能就是队列满了。 - 更精准的做法是用
ss -lnt查看监听套接字的Send-Q和Recv-Q,当Recv-Q长期等于甚至大于Send-Q时,半连接队列大概率已经溢出。
我自己的习惯是同时看/proc/net/netstat里的ListenOverflows字段,这个值非零的话,就直接实锤了。
应急处理:临时增大队列和缩短超时
确认是半连接队列的问题后,第一反应是别硬扛,要“扩容”,Linux下可以分两步走。
- 调大队列上限:
sysctl -w net.ipv4.tcp_max_syn_backlog=2048,同时配合sysctl -w net.core.somaxconn=2048,因为应用层监听队列(backlog)受它限制。 - 让半连接更快被回收:调小
net.ipv4.tcp_synack_retries,默认5次重试太磨叽,改成1或2,服务器在更短时间内放弃等待,释放队列槽位。
这两个操作只能算是临时止血,如果你用的是nginx,还要确认listen指令后面的backlog参数足够大,否则内核扩容了应用层接收不到,照样丢包。
长期防御:从源头到边缘层层设防
应急操作救不了运营中的网站,真正的防御需要在网络链路上做文章。
- 在防火墙或路由器上做SYN限速:限制每秒来自同一IP的SYN包数量,或者直接丢弃源IP伪造明显的包,攻击者虽然会换源IP,但至少能挡住一部分初级攻击。
- 启用SYN Proxy:不少高防IP和CDN厂商会在边缘节点先替你完成TCP握手,只有确认客户端确实存在后,才把连接转发回源站,这样源站的半连接队列永远不直接暴露在攻击面里。
- 把源站放到负载均衡后面,让LB扛流量,LB本身也会做SYN Flood防护,像LVS的SYN Proxy模块就是干这个的。
服务器半连接队列大小如何查看与调整?
这个问题很多朋友问过,我直接给出具体路径。
- 查看当前半连接队列最大长度:
cat /proc/sys/net/ipv4/tcp_max_syn_backlog - 查看队列溢出次数:
cat /proc/net/netstat,注意看ListenOverflows这一行。 - 临时修改:
sysctl -w net.ipv4.tcp_max_syn_backlog=4096 - 永久生效:把参数写进
/etc/sysctl.conf,然后执行sysctl -p。
需要说明的是,盲目调太大也有副作用,队列太长意味着能容纳的半连接更多,但同时也会占用内存,并且让合法连接在排队时等待更久,业内专家指出,生产环境建议先压测再调整,别一上来就给几万。
能不能靠tcp_syncookies硬扛?
能,但要想清楚代价。sysctl -w net.ipv4.tcp_syncookies=1开启了SYN Cookie机制,服务器不再把SYN放入半连接队列,而是根据连接信息生成一个Cookie放在SYN-ACK里,等客户端回ACK时再验证。
好处是队列满时也能接受新连接,坏处是它不适合高流量下的性能敏感场景,而且会破坏部分TCP扩展特性,比如时间戳,所以我的建议是:应急时可以开,但别指望它当长期盾牌。
为什么有时队列没满服务也不可用?
半连接队列被占满是常见原因,但服务不可用也可能是多重因素叠加,攻击流量同时涌来时,带宽会被打满,CPU也可能因为处理海量SYN包而飙高,有时候队列只是接近上限,没有全满,但网络层已经拥堵到正常请求根本进不来,这时候单独调队列参数已经没意义,得从带宽清洗和流量封锁入手,换句话说,半连接队列是压垮骆驼的那根稻草,但背后的骆驼可能是整个网络链路。
回到根本,SYN Flood真正可怕的地方在于它抓住TCP握手机制的设计弱点,用极低成本消耗服务器的核心资源,半连接队列只是最容易被击穿的那道门,一旦失守,外面正常访问的用户全都被堵在门外。
关于SYN Flood半连接队列的常见疑问
SYN Flood攻击中半连接队列满了会怎样?
队列满了之后,内核会拒绝新到的SYN包,正常用户无法完成TCP三次握手,表现为网站超时、连接被重置,攻击期间服务器除了这个队列被塞满外,其他部件往往还是正常的,这也是SYN Flood容易让人误判的地方。
Linux半连接队列默认多大?如何修改?
Linux的默认值由net.ipv4.tcp_max_syn_backlog控制,常见发行版设置在128到1024之间,具体取决于内存大小和内核版本,修改方法是通过sysctl命令临时调整,或写入/etc/sysctl.conf永久生效,注意net.core.somaxconn同样会影响监听队列,修改时最好一起调整。
tcp_syncookies能完全防住SYN Flood吗?
不能,SYN Cookie能避免半连接队列被耗尽,但攻击者如果持续发送高强度SYN包,服务器的CPU和带宽依然会被消耗,攻击效果只是从“连接建立失败”变成“响应变慢”,它适合作为紧急缓解措施,真正的防护还需要依赖流量清洗和边缘抗D设备。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/788086.html


