调整内核参数是防御SYN Flood攻击最直接、成本最低的手段之一。面对SYN半连接队列被占满、服务器无法响应正常请求的情况,核心思路不是无限增大队列,而是缩短半连接的等待时间、加速回收无效资源,同时启用SYN Cookie机制,让服务器在队列满时仍能通过算法验证并响应合法连接。

首先要动的是两个关键参数:net.ipv4.tcp_synack_retries和net.ipv4.tcp_syn_retries。前者控制服务器在发送SYN+ACK后,未收到客户端ACK时的重试次数,默认值是5,意味着半连接会存在非常久。直接把它降到1或2,能大幅缩短半连接存活时间。后者控制客户端发起连接时的SYN重试次数,服务器端同样可以调低,减少自身对外发起连接时的资源占用。

# 降低SYN+ACK重试次数,默认5,建议设为1或2
net.ipv4.tcp_synack_retries = 1

# 降低SYN重试次数,默认6,建议设为2
net.ipv4.tcp_syn_retries = 2

接下来是SYN Cookie。当半连接队列满时,内核默认会直接丢弃新的SYN包。开启tcp_syncookies后,服务器不再为每个SYN分配完整的半连接资源,而是根据客户端IP、端口、时间戳和密钥计算出一个Cookie,编码进SYN+ACK的初始序列号中。收到客户端ACK时,反向验证这个Cookie,合法则直接建立连接,跳过半连接队列。这个机制在攻击流量下能保证正常用户仍有概率连接成功。

# 启用SYN Cookie防护
net.ipv4.tcp_syncookies = 1

半连接队列大小的正确调整方式

很多人上来就调大net.core.somaxconn和net.ipv4.tcp_max_syn_backlog,但这只是延缓队列被填满的时间,并不能根治问题。而且队列过大,每个半连接仍会占用内存和CPU资源,在真实洪水攻击面前意义不大。正确的做法是先启用SYN Cookie,再根据业务实际并发量合理设置队列上限。somaxconn是全系统监听套接字的最大挂起连接数,tcp_max_syn_backlog是SYN_RECV状态的最大半连接数,两者取较小值生效。

# 全系统最大挂起连接数,默认128,建议根据业务调整
net.core.somaxconn = 2048

# SYN_RECV状态半连接上限,默认值因内核版本而异
net.ipv4.tcp_max_syn_backlog = 2048

tcp_abort_on_overflow的取舍

这个参数控制的是全连接队列溢出时的行为。全连接队列存放的是已完成三次握手、等待应用accept()的连接。当它满时,默认行为是服务器直接丢弃客户端发来的ACK,客户端会以为丢包而重传,服务器在重传时如果队列有空位则恢复连接。这看起来是种柔性处理,但在攻击场景下,大量攻击请求已完成握手并占满全连接队列,正常用户的ACK同样被丢弃,体验极差。开启tcp_abort_on_overflow会让服务器直接发RST重置连接,客户端立刻得到失败反馈,可以快速尝试其他服务器或重连。在明确遭受攻击时,设为1能更快释放资源,但正常高负载下可能导致连接成功率下降,需要结合监控判断。

# 全连接队列溢出时直接发RST,默认0,攻击时可临时开启
net.ipv4.tcp_abort_on_overflow = 0

连接追踪表与防火墙协同

SYN Flood攻击不仅消耗TCP协议栈资源,还会撑爆netfilter的连接追踪表。每个经过防火墙的连接都会在nf_conntrack表中留下记录,攻击流量会迅速填满这张表,导致正常连接被丢弃。调大连接追踪表上限、缩短超时时间是必要操作。

# 连接追踪表最大条目数,根据内存调整
net.netfilter.nf_conntrack_max = 2097152

# 缩短TCP连接追踪超时,尤其是TIME_WAIT和ESTABLISHED
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 30
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 30
net.netfilter.nf_conntrack_tcp_timeout_established = 600
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30

在iptables层面,可以利用recent模块做简单的速率限制。对每个源IP的新建连接数做限制,超过阈值的直接丢弃,能过滤掉大量低强度攻击。但要注意,高强度的分布式攻击源IP分散,单纯基于IP的限速效果有限,需要结合更上层的流量清洗方案。

# 示例:限制每个IP每秒最多10个新连接,超出则丢弃
iptables -A INPUT -p tcp --syn -m state --state NEW \
  -m recent --name synflood --set
iptables -A INPUT -p tcp --syn -m state --state NEW \
  -m recent --name synflood --update --seconds 1 --hitcount 10 -j DROP

TCP时间戳与PAWS机制的利用

tcp_timestamps默认开启,它有两个作用:RTTM(往返时间测量)和PAWS(防止序列号回绕)。在防御SYN Flood时,时间戳选项能帮助内核更快地识别和丢弃伪造的SYN包。攻击者如果伪造源IP,其时间戳值往往不连续或异常,内核可以据此做快速判断。但要注意,在NAT环境下时间戳可能导致连接问题,如果后端有大量NAT设备,需要评估是否关闭。

# 默认开启,通常建议保持
net.ipv4.tcp_timestamps = 1

tcp_fastopen的潜在风险

TFO(TCP Fast Open)允许在SYN包中携带数据,减少一次往返。但在遭受SYN Flood时,TFO会让服务器在握手完成前就处理数据,增加CPU开销。如果不需要TFO带来的延迟优化,建议关闭它以减少攻击面。

# 关闭TCP Fast Open,减少攻击面
net.ipv4.tcp_fastopen = 0

监控与验证手段

参数调整后,必须用数据验证效果。ss -s可以快速查看当前TCP状态分布,重点关注SYN-RECV数量是否异常。netstat -s | grep -i syn能输出SYN相关的统计计数器,包括SYN Cookie的触发次数、半连接队列溢出次数等。如果看到tcp_syncookies_sent和tcp_syncookies_recv计数持续增长,说明SYN Cookie正在生效,攻击流量确实存在。

# 查看TCP状态汇总
ss -s

# 查看SYN相关统计
netstat -s | grep -i syn

另一个容易被忽略的指标是CPU软中断。SYN Flood攻击会触发大量网卡中断和协议栈处理,导致ksoftirqd进程CPU占用飙升。通过top或mpstat观察si(软中断)占用率,如果持续超过20%,说明协议栈层面压力巨大,单纯内核参数调优可能已不够,需要引入DPDK或XDP等内核旁路方案,或者在上游部署专业的流量清洗设备。

综合来看,Debian下防御SYN Flood的内核参数调优是一个分层策略:第一层用SYN Cookie和缩短重试次数快速回收半连接资源;第二层合理设置队列上限并控制全连接队列溢出行为;第三层用连接追踪表限制和iptables速率限制做初步过滤;第四层通过监控验证效果并决定是否需要更上层防护。这些参数调整后需执行sysctl -p使其立即生效,并写入/etc/sysctl.conf或/etc/sysctl.d/下的配置文件以保证重启后不丢失。