服务器在遭受高频短连接攻击时,最直观的现象是连接表被迅速占满,大量socket处于TIME_WAIT或SYN_RECV状态,正常用户的请求无法建立新的TCP握手。这种攻击并不依赖巨大的带宽,而是通过海量的、短暂的、合法的TCP连接请求来耗尽内核的跟踪资源。在Debian系统下,默认的内核参数是为了通用场景设置的,面对这种特定类型的资源耗尽攻击,必须进行针对性的深度调优。

理解攻击向量与内核的关联

高频短连接攻击主要瞄准两个软肋。第一是conntrack表,也就是连接跟踪表。内核需要记录每一个经过网络栈的连接状态,即使是拒绝的连接,在排查阶段也会短暂占用表项。当攻击者以极高频率发送伪造源IP的SYN包时,conntrack表会在几秒内爆满,导致后续所有包被丢弃。第二是本地端口的快速回收问题。如果攻击是针对本机服务,大量主动关闭的连接会滞留在TIME_WAIT状态,迅速耗尽可用的临时端口,或者导致socket的hash表冲突激增,CPU软中断占用飙升。优化必须同时从这两方面入手。

加固连接跟踪表,防止conntrack溢出

netfilter的连接跟踪模块是抵御此类攻击的第一道防线,也是最脆弱的环节。默认的conntrack_max通常根据内存自动计算,但在攻击流量下这个值远远不够。我们需要手动增大上限,并让内核在表满时采取更激进的丢弃策略。

# 查看当前连接跟踪表大小和当前使用量
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count

直接提高最大跟踪连接数,这个值取决于物理内存,每一条跟踪大约占用300字节左右。对于8GB内存的服务器,设置一个较高的值可以争取更多处理时间。

# 设置最大连接跟踪数,例如设置为2097152
sysctl -w net.netfilter.nf_conntrack_max=2097152

更关键的参数是nf_conntrack_tcp_timeout_syn_recv和nf_conntrack_tcp_timeout_syn_sent。攻击者在发送第一个SYN后往往不会完成三次握手,大量的半开连接会长时间占用表项。默认的超时时间过长,必须大幅缩短,让无效的半开连接快速被内核清理掉。

# 将SYN_RECV状态的超时从默认的60秒降低到10秒
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=10

# 将SYN_SENT状态的超时从默认的120秒降低到10秒
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=10

当连接跟踪表确实被填满时,内核的行为由nf_conntrack_buckets和net.netfilter.nf_conntrack_generic_timeout等参数控制。但更直接有效的是开启TCP时间戳和重用机制,并结合SYN Cookie来从源头减少不必要的跟踪条目。对于不需要进行NAT的纯Web服务器,如果确认没有使用iptables的nat表规则,甚至可以彻底卸载nf_conntrack模块,但通常建议保留并优化。

调优TCP协议栈,加速短连接回收

高频短连接攻击如果是针对本机服务,比如HTTP的80端口,那么本地会产生大量的TIME_WAIT状态。TIME_WAIT是TCP协议保证可靠关闭的必要机制,但在攻击场景下,2MSL的等待时间会成为灾难。我们需要让内核能够快速回收处于TIME_WAIT状态的socket,并允许端口复用。

# 开启TCP时间戳,有助于精确计算RTT和快速回收
sysctl -w net.ipv4.tcp_timestamps=1

# 开启快速回收TIME_WAIT状态的连接,需配合tcp_timestamps使用
sysctl -w net.ipv4.tcp_tw_recycle=1

# 注意:在较新的Debian内核中,tcp_tw_recycle已被移除,因为它对NAT设备后的客户端不友好。
# 对于现代内核,应重点使用tcp_tw_reuse
sysctl -w net.ipv4.tcp_tw_reuse=1

tcp_tw_reuse允许内核将处于TIME_WAIT状态的socket用于新的客户端连接,这在服务端主动关闭连接的高并发场景下极其有效。同时,我们需要扩大本地临时端口的范围,如果服务器需要作为客户端去连接后端,例如反向代理场景,端口范围过小会迅速耗尽。

# 扩大本地临时端口范围,从默认的32768-60999扩大到1024-65535
sysctl -w net.ipv4.ip_local_port_range="1024 65535"

对于TIME_WAIT状态的最大数量,虽然不能直接硬性限制,但可以通过调整tcp_max_tw_buckets来控制。当TIME_WAIT连接数超过这个阈值时,内核会立即销毁多余的连接,并打印警告日志。在攻击期间,这能防止系统因跟踪大量TIME_WAIT而崩溃。

# 设置TIME_WAIT桶的最大数量,例如设置为262144
sysctl -w net.ipv4.tcp_max_tw_buckets=262144
启用并强化SYN Cookie机制

SYN Cookie是抵御SYN Flood攻击的核心机制。当系统的SYN队列满时,内核会使用加密的Cookie来响应SYN请求,而无需在内存中分配完整的连接跟踪资源,直到收到客户端的最终ACK才真正建立连接。这能从根本上对抗半开连接攻击。

# 开启SYN Cookies
sysctl -w net.ipv4.tcp_syncookies=1

# 调整SYN队列的最大长度,这个队列是等待三次握手完成的半连接队列
sysctl -w net.ipv4.tcp_max_syn_backlog=8192

# 调整处于SYN_RECV状态的最大连接数
sysctl -w net.ipv4.tcp_max_syn_backlog=16384

SYN Cookie并非完全没有代价,它会禁用部分TCP高级特性,如窗口缩放,但在攻击期间,保证服务可用性远比性能优化重要。在Debian系统中,一旦启用SYN Cookie,当SYN队列压力大时内核会自动触发,无需人工干预。

优化孤儿socket与文件描述符限制

攻击可能导致大量的socket处于CLOSE_WAIT或LAST_ACK等状态,如果应用层没有及时关闭,这些孤儿socket会消耗内核内存。我们需要限制孤儿socket的数量,并确保系统的文件描述符上限足够高,避免出现“Too many open files”错误。

# 设置系统中允许的孤儿socket最大数量,超出后会被内核复位
sysctl -w net.ipv4.tcp_max_orphans=65536

# 调整系统级文件描述符上限
sysctl -w fs.file-max=6553560

# 同时需要在/etc/security/limits.conf中设置用户级限制
# * soft nofile 65535
# * hard nofile 65535

对于服务进程,比如Nginx或HAProxy,还需要在它们的配置文件中单独提高worker进程的nofile限制,确保每个进程能打开足够的socket。

调整网络核心参数,提升包处理效率

当攻击流量到达网卡时,如果内核的软中断处理不过来,即使连接跟踪还有余量,也会导致丢包。我们需要调整网卡队列和软中断相关的参数,让CPU能更高效地处理网络数据包。

# 增加网卡接收队列的长度,让网卡能缓存更多待处理的包
sysctl -w net.core.netdev_max_backlog=5000

# 增大socket的接收和发送缓冲区最大值
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216

# 调整TCP读写缓冲区的最小、默认和最大值
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

在多核服务器上,确保网卡的中断请求均匀分布到各个CPU核心,避免单核过载。这通常需要结合硬件队列和irqbalance服务进行调整,但从内核层面,可以开启RPS和RFS来分散负载。

# 开启接收数据包转向(RPS),将处理分散到多个CPU
# 以下示例为eth0网卡设置RPS,具体值取决于CPU核心数
echo f > /sys/class/net/eth0/queues/rx-0/rps_cpus

# 开启接收流转向(RFS),确保同一流的数据包在同一CPU上处理
sysctl -w net.core.rps_sock_flow_entries=32768
使用iptables限制连接速率

内核参数优化提供了更大的缓冲池和更快的回收速度,但要精准拦截恶意源,还需要在netfilter层面进行速率限制。利用iptables的recent和hashlimit模块,可以对单个IP的连接频率进行控制,将攻击流量阻挡在连接跟踪表之前。

# 使用hashlimit模块限制每个源IP到80端口的新建连接速率
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m hashlimit \
  --hashlimit-name http_limit --hashlimit-above 50/sec --hashlimit-burst 100 \
  --hashlimit-mode srcip -j DROP

# 使用recent模块记录并封禁短时间内发起大量请求的IP
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update \
  --seconds 60 --hitcount 30 -j DROP

这些规则能在攻击流量进入协议栈之前就将其丢弃,极大地减轻了内核协议栈和连接跟踪模块的压力。需要注意的是,hashlimit和recent模块本身也会消耗少量内存和CPU,要合理设置阈值,避免误伤正常用户。

持久化配置与监控验证

所有通过sysctl命令调整的参数在重启后都会失效,必须写入配置文件。在Debian系统中,将参数写入/etc/sysctl.conf或者/etc/sysctl.d/目录下的自定义配置文件,例如/etc/sysctl.d/99-anti-ddos.conf。

# 将以上所有优化参数汇总写入配置文件
cat >> /etc/sysctl.d/99-anti-ddos.conf << EOF
net.netfilter.nf_conntrack_max = 2097152
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 10
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 10
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_max_orphans = 65536
fs.file-max = 6553560
net.core.netdev_max_backlog = 5000
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rps_sock_flow_entries = 32768
EOF

# 应用配置
sysctl -p /etc/sysctl.d/99-anti-ddos.conf

优化完成后,必须持续监控连接跟踪表的使用情况、TIME_WAIT状态的数量以及CPU软中断的占用率。使用conntrack -S命令查看统计,ss -s查看socket概要,mpstat -P ALL 1观察每个CPU核心的软中断分布。如果发现某个核心的si占用率持续超过20%,需要进一步调整网卡队列和RPS配置。如果conntrack表使用率仍然接近100%,说明单纯的参数调整已经不足以应对攻击规模,此时应考虑在上游引入专业的DDoS清洗设备或服务,但在绝大多数场景下,上述内核级优化已经能够将服务器的抗短连接攻击能力提升数倍,为后续的自动化防御策略争取宝贵的反应时间。