在面对大流量SYN洪水攻击时,synproxy是目前Linux内核层面最高效的防御手段之一。它的核心原理并不复杂——在TCP三次握手完成之前,由内核代理代替真实服务器完成SYN-ACK的回复,只有当客户端回传ACK确认后,才把连接真正转发给后端服务。这样一来,攻击流量中大量伪造源IP的SYN包根本无法完成握手,半开连接被消耗在代理层,真实服务器的资源得到保护。下面我会从原理、配置、调优、局限性几个维度,把synproxy在DDoS防护中的实战用法讲透。
一、SYN洪水攻击的本质和为什么需要synproxy
SYN洪水属于经典的四层DDoS攻击。攻击者发送海量SYN包,但故意不回最后一步ACK。服务器收到SYN后会分配资源(TCB条目)进入SYN_RECV状态,等待超时重传。当半开连接数量超过系统承载极限,正常用户的连接请求就会被拒绝。传统的SYN Cookie机制虽然有效,但在超高并发场景下会增加CPU开销,而且对某些需要保持状态的应用不友好。synproxy的优势在于它把状态维护和连接代理的工作全部放在内核的netfilter框架里完成,效率远高于用户态的防护方案。
二、synproxy的工作机制详解
synproxy工作在TCP代理模式下,本质上是一个内核级的TCP中继。当一个SYN包到达时,synproxy不会立即转发给后端,而是自己生成一个SYN-ACK回复给客户端,并记录这个半开连接的状态。如果客户端是真实的,它会回传ACK,synproxy收到后验证序列号,确认合法,再把完整的TCP连接建立到后端服务器。如果客户端是伪造IP或者根本不回ACK,这个半开连接在超时后自动清除,不会占用后端任何资源。整个过程对后端应用完全透明,后端看到的就是正常的已建立连接。
三、iptables/nftables中配置synproxy的具体方法
在iptables中启用synproxy非常直接,核心规则如下:
# 允许新的TCP连接经过synproxy(以80端口为例) iptables -t raw -A PREROUTING -p tcp --dport 80 --syn -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 # 对已经通过synproxy验证的连接正常转发 iptables -t raw -A PREROUTING -p tcp --dport 80 -j ACCEPT # 如果synproxy未匹配到(比如非SYN包),交给后续链处理 iptables -A INPUT -p tcp --dport 80 -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j DROP
如果使用nftables(较新的Linux发行版推荐),配置方式如下:
table ip filter {
chain input {
type filter hook input priority 0; policy drop;
# 对新的SYN包启用synproxy
tcp dport 80 flags syn tproxy to :80
# 允许已建立的连接
ct state established,related accept
}
}
需要特别注意的是,synproxy必须放在raw表的PREROUTING链中,因为它需要在连接跟踪之前介入。如果放在filter表或者INPUT链,可能无法正常工作或者产生意外行为。
四、关键参数调优和性能优化
synproxy不是开了就万事大吉,参数调优直接决定防护效果和系统性能。几个关键参数需要重点关注:
第一是--sack-perm,启用SACK Permitted选项,允许客户端使用选择性确认,这对现代TCP通信很重要,能提升传输效率。第二是--timestamp,开启时间戳选项,防止序列号回绕攻击,同时也有助于连接追踪。第三是--wscale 7,窗口缩放因子设为7,对应128倍的窗口大小,适合高带宽环境。第四是--mss 1460,最大分段大小设为1460字节,这是以太网MTU 1500减去IP和TCP头部后的标准值,避免分片。
在内核层面还需要调整几个sysctl参数来配合synproxy工作:
# 增大SYN队列长度 net.ipv4.tcp_max_syn_backlog = 65536 # 开启SYN Cookie作为兜底(synproxy为主,cookie为辅) net.ipv4.tcp_syncookies = 1 # 减少SYN重试次数,加快半开连接回收 net.ipv4.tcp_synack_retries = 2 # 增大半开连接超时时间(单位秒),给synproxy更多验证窗口 net.ipv4.tcp_syn_recv_retries = 3 # 开启TCP Fast Open(可选,提升性能) net.ipv4.tcp_fastopen = 3
这些参数的调整需要根据实际服务器的内存和CPU情况来定。synproxy本身会占用内核内存来维护半开连接表,如果攻击流量极大,半开连接数量可能飙升到数十万级别,此时需要确保系统有足够的可用内存。
五、synproxy的适用场景和最佳实践
synproxy最适合的场景是:单台服务器或少量服务器需要防护SYN洪水,且没有硬件防火墙或高防IP的情况。它特别适合Web服务器(HTTP/HTTPS)、游戏服务器、API网关等TCP服务。在实际部署中,建议把synproxy规则放在最前面,配合限速规则使用,形成多层防护:
第一层:在网络入口处用hashlimit对SYN包速率做初步限制,比如每秒不超过1000个新连接。第二层:synproxy处理通过限速的合法SYN请求。第三层:对已建立连接做应用层WAF检测。这样分层处理可以避免synproxy在极端攻击下被压垮。
另外,如果你的服务器同时运行UDP服务或者需要处理大量短连接,要注意synproxy只对TCP有效。对于UDP洪水,需要配合其他机制如conntrack的UDP超时调整或者直接在上游清洗。
六、synproxy的局限性和需要注意的坑
synproxy并非万能。第一个局限是它只支持TCP协议,对UDP、ICMP等其他协议的DDoS无效。第二个局限是它会引入额外的延迟,因为多了一次内核代理的往返,在对延迟极度敏感的场景(如高频交易)需要评估是否可接受。第三个局限是在极端大流量下,比如每秒数百万SYN包,单台服务器的synproxy可能依然扛不住,这时必须依赖上游的流量清洗服务或CDN层面的防护。
还有一个容易踩的坑:synproxy和conntrack模块存在资源竞争。当半开连接数量过大时,conntrack表可能被填满,导致所有连接(包括合法的)都被丢弃。解决办法是适当增大conntrack表的大小:
# 增大conntrack最大数量 net.netfilter.nf_conntrack_max = 1048576 # 或者在较新内核中 echo 1048576 > /proc/sys/net/netfilter/nf_conntrack_max
此外,如果你的后端服务使用了非标准的TCP选项或者有特殊的 keepalive 需求,synproxy可能会干扰这些行为,需要在测试环境充分验证后再上线。
七、监控和效果评估
部署synproxy后,必须建立监控体系。重点关注以下指标:半开连接数量(通过conntrack -L查看)、SYN包速率变化、后端服务器的连接建立成功率、系统CPU和内存使用率。如果发现半开连接持续增长不回落,说明攻击仍在持续且synproxy正在正常工作;如果后端连接数骤降,可能是synproxy参数配置有误或者内核资源不足。推荐使用ss命令实时查看连接状态:
# 查看当前SYN_RECV状态的连接数 ss -tan state syn-recv | wc -l # 查看synproxy相关的连接追踪条目 conntrack -L -p tcp --state SYN_RECV | wc -l # 实时监控每秒新增连接 watch -n 1 'ss -tan state syn-recv | wc -l'
八、总结和建议
synproxy是Linux服务器对抗SYN洪水攻击最实用的内核级方案,配置简单、开销可控、效果显著。但它不是银弹,需要配合限速、conntrack调优、上游清洗等多层策略才能构建完整的防护体系。在实际操作中,先在测试环境压测验证,再逐步灰度上线,避免配置失误导致正常业务中断。对于日均流量超过10Gbps的业务,建议还是优先考虑专业的DDoS清洗服务,synproxy作为最后一道本地防线来使用。
掌握synproxy的配置和调优,是每一个运维工程师和安全从业者的基本功。它不需要额外安装软件,不需要购买设备,只需要几条iptables规则和几个内核参数,就能让你的服务器在面对SYN洪水时多一层坚实的铠甲。把这些细节做到位,大部分中小规模的SYN攻击都能被有效化解。
