SYN Flood攻击之所以难缠,是因为它利用了TCP三次握手机制中服务器必须为半开连接分配资源的特性。攻击者发送海量伪造源IP的SYN包,服务器响应SYN-ACK后,由于源IP不可达,永远等不到最后的ACK,导致半连接队列被占满,正常用户无法建立新连接。这种攻击属于资源耗尽型,单纯依靠防火墙拦截有时会因误杀率高或处理性能瓶颈而失效,因此调整Linux内核的网络参数,让系统在面对突发SYN流量时更具弹性,是纵深防御中成本最低且最直接的一环。
启用并优化SYN Cookie机制SYN Cookie是应对SYN Flood最经典的内核级防线。它的核心原理是当半连接队列满时,服务器不再为新的SYN请求分配完整的TCB(传输控制块)资源,而是将连接状态编码成一个加密的Cookie,作为SYN-ACK包的初始序列号发回。当收到客户端返回的ACK时,服务器验证Cookie有效性,若通过则重建连接。这彻底解决了内存耗尽问题。
检查当前状态:
sysctl net.ipv4.tcp_syncookies
如果输出为0,必须立即开启:
sysctl -w net.ipv4.tcp_syncookies=1
仅开启还不够,需要配合调整触发阈值。参数net.ipv4.tcp_max_syn_backlog决定了半连接队列的最大长度。默认值通常较小,在高并发或攻击场景下,队列很快被填满,导致SYN Cookie频繁触发,虽然能抗攻击,但Cookie验证也会消耗CPU。建议根据内存大小适度调高此值,例如设为8192或更高:
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
但要注意,调高队列意味着在攻击初期系统会尝试消耗更多内存来维护半连接,如果攻击流量巨大,内存可能先于CPU耗尽。因此需要结合SYN Cookie的触发逻辑,让系统在队列接近满载时平滑切换到Cookie模式。从Linux 3.6内核开始,SYN Cookie已支持TCP时间戳和窗口缩放等选项,兼容性大大提升,开启后几乎无副作用,应作为默认开启项。
调整重传次数与超时时间攻击者发送SYN后不会响应SYN-ACK,服务器会进行多次重传,默认重传次数为5次,总耗时约180秒。这意味着一个无效的半连接会在队列中驻留长达3分钟。在攻击期间,这会导致资源被长时间无效占用。降低重传次数能加速无效连接的清理。
参数net.ipv4.tcp_synack_retries控制SYN-ACK包的重传次数。将其从默认的5减至1或2,可将半连接存活时间压缩到10秒以内:
sysctl -w net.ipv4.tcp_synack_retries=1
同样,对于已建立的连接,如果遭遇ACK Flood或中间网络中断,服务器也会重传数据包。参数net.ipv4.tcp_retries2控制数据包重传次数,默认15次,在攻击背景下可适当调低至5-8次,加速释放僵死连接占用的文件描述符和内存。但需注意,调得过低可能导致弱网环境下正常连接被误断,建议先在非核心业务上验证。
此外,net.ipv4.tcp_fin_timeout控制FIN-WAIT-2状态下的等待时间,默认60秒。在连接数暴涨时,大量处于FIN-WAIT-2的socket会耗尽内存。将其降至30秒甚至15秒,能加快端口回收:
sysctl -w net.ipv4.tcp_fin_timeout=30扩大连接跟踪表与优化其行为
Netfilter的连接跟踪模块(conntrack)会为每个经过主机的连接维护状态,包括SYN包。当攻击流量巨大时,连接跟踪表首先被占满,表现为内核日志出现“nf_conntrack: table full, dropping packet”错误,正常包被丢弃。此时即使TCP栈做了优化,包在到达TCP层之前就被netfilter丢弃了。
增大哈希表大小是直接手段,参数net.netfilter.nf_conntrack_max控制最大跟踪条目数,net.netfilter.nf_conntrack_buckets控制哈希桶数量。桶数量应为最大条目数的1/4到1/2,以确保查找效率。例如,将最大条目数设为2097152:
sysctl -w net.netfilter.nf_conntrack_max=2097152
同时,必须缩短跟踪条目的超时时间,否则表再大也会被填满。SYN_SENT和SYN_RECV状态的超时时间尤为重要:
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=30 sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=30
默认SYN_SENT超时可能长达120秒,攻击期间必须大幅缩短。另外,开启net.netfilter.nf_conntrack_tcp_loose=0可禁用松散模式,让conntrack更严格地校验TCP序列号,丢弃不符合窗口范围的包,这能过滤掉部分伪造的ACK攻击,但对SYN Flood本身效果有限。
优化本地端口范围与TIME-WAIT复用当服务器自身作为客户端发起连接,或反向代理场景下,大量TIME-WAIT状态的连接会耗尽本地端口。SYN Flood攻击期间,正常服务的出站连接也可能因端口不足而失败。扩大可用端口范围:
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
默认值通常从32768开始,调整为从1024开始能增加约3万个可用端口。同时,在严格受控的内网环境下,可开启TIME-WAIT套接字复用:
sysctl -w net.ipv4.tcp_tw_reuse=1
注意,tcp_tw_reuse只对客户端侧有效,且要求时间戳开启。对于纯粹接收大量外部连接的服务器,更有效的是开启net.ipv4.tcp_tw_recycle,但此参数从Linux 4.12起已被移除,因为它会破坏NAT环境下的连接。所以现代内核下,应专注于快速回收TIME-WAIT连接,通过降低tcp_fin_timeout和启用tcp_tw_reuse来缓解端口压力。
启用TCP Fast Open减少握手开销TCP Fast Open(TFO)允许客户端在发送SYN包时携带数据,服务器验证Cookie后可在收到ACK前就开始处理请求。这虽不能直接防御SYN Flood,但能大幅降低正常用户的连接延迟,使得在攻击期间,合法请求能以更少的握手次数完成,间接提升了服务的抗冲击能力。开启TFO:
sysctl -w net.ipv4.tcp_fastopen=3
值为3表示同时开启客户端和服务器端支持。TFO需要应用层配合,如Nginx配置listen 80 fastopen=256;,但内核层面必须首先启用。
调整队列缓存与背压机制当网卡收到的包速率超过内核处理能力时,包会被暂存在接收队列中。参数net.core.netdev_max_backlog控制每个CPU的接收队列长度,默认1000。在SYN Flood攻击下,中断风暴会导致软中断处理不过来,增大此值可减少丢包:
sysctl -w net.core.netdev_max_backlog=5000
同时,应用层的监听套接字也有自己的连接队列,即全连接队列,由net.core.somaxconn和listen()函数的backlog参数共同决定。增大somaxconn能让已完成三次握手的连接更快被accept()取走,避免全连接队列溢出:
sysctl -w net.core.somaxconn=4096
在SYN Cookie生效期间,半连接队列实际上被绕过了,但全连接队列的容量决定了正常连接建立后能否被及时处理,两者配合才能保证端到端的通畅。
组合策略与验证方法单一参数调整往往效果有限,必须形成组合拳。一个典型的防御性内核参数配置如下:
# 开启SYN Cookie net.ipv4.tcp_syncookies = 1 # 增大半连接队列 net.ipv4.tcp_max_syn_backlog = 16384 # 减少SYN-ACK重传次数 net.ipv4.tcp_synack_retries = 1 # 减少数据重传次数 net.ipv4.tcp_retries2 = 5 # 加速FIN-WAIT-2回收 net.ipv4.tcp_fin_timeout = 15 # 扩大连接跟踪表 net.netfilter.nf_conntrack_max = 2097152 net.netfilter.nf_conntrack_buckets = 524288 # 缩短连接跟踪超时 net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 20 net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20 net.netfilter.nf_conntrack_tcp_timeout_established = 600 # 扩大本地端口范围 net.ipv4.ip_local_port_range = 1024 65535 # 开启TIME-WAIT复用 net.ipv4.tcp_tw_reuse = 1 # 增大接收队列 net.core.netdev_max_backlog = 8192 # 增大全连接队列 net.core.somaxconn = 4096 # 开启TCP Fast Open net.ipv4.tcp_fastopen = 3
验证配置是否生效,可在攻击测试中观察半连接队列溢出次数:
netstat -s | grep "SYNs to LISTEN"
以及连接跟踪表的使用情况:
conntrack -S
如果溢出计数持续增长,说明队列仍不够大或Cookie未正确触发。如果连接跟踪表频繁满载,需进一步增大max值或缩短超时。实际调优中,建议先在测试环境用hping3等工具模拟SYN Flood,逐步调整参数,找到内存、CPU和抗攻击能力之间的最佳平衡点。切记,内核参数调优是缓解手段,不能替代边界流量清洗和业务层限流,但它能极大提升服务器在攻击下的生存能力,为上层防御争取宝贵的响应时间。
