传输层防护做TCP异常握手限速与验证,本质上是在半连接队列被耗尽之前,用规则挡住无效握手请求、用算法确认真实客户端,从而保住正常业务的连接通道。无论是自建机房的Linux服务器,还是接入高防IP的云上业务,TCP异常握手处理不好,最先崩掉的往往是负载均衡层和源站的内核协议栈,下面直接拆解防护思路、操作路径和验证方法。
TCP异常握手怎么防护,先搞清限速和验证各自解决的问题
从抓包视角看,一个正常的TCP会话要经历SYN、SYN-ACK、ACK三次握手,攻击者利用的恰恰是第三步的缺失,或者第一步的伪造,异常握手最常见的就是SYN Flood:客户端只发SYN,不回应SYN-ACK,导致服务器内核的半连接队列被占满,新来的正常SYN直接被丢弃,行业共识认为,真正有效的防护不是把攻击流量全部拦截,而是让服务器在异常流量面前仍然有资源响应合法用户。
限速解决的是资源耗尽问题,验证解决的是请求真伪问题。 两者缺一不可,限速做得再狠,如果验证逻辑不识别伪造源IP,攻击者换个端口继续打,照样能把连接表打满,反过来,验证算法再聪明,如果限速阈值设置过高,攻击流量照样能冲破队列防线。
- 限速层面:限制单位时间内同一源IP发起的SYN包数量,超出阈值直接丢包或加入黑名单。
- 验证层面:启用SYN Cookie机制,不分配半连接资源,用Cookie携带连接信息,收到客户端ACK后再还原连接。
- 两者配合:先让验证机制兜底,再让限速规则把资源消耗控制在安全水位。
Linux源站自建防护,限速和验证的具体落法
防护动手之前,先看当前内核状态,通过 ss -s 可以看到当前TCP套接字分布,重点关注 syns 和 timeserver 字段。netstat -s 输出里如果出现大量 SYN to SYN+ACK 的重传计数,说明半连接队列已经出现丢包,这时候再上防护已经有点被动,但总比裸奔强。
第一步:调整内核参数,让验证机制先跑起来
多数Linux发行版默认开启SYN Cookie,但有些安全加固模板会把它关掉,先确认再启动:
# 查看当前状态,1表示开启,0表示关闭 sysctl net.ipv4.tcp_syncookies # 临时开启 sysctl -w net.ipv4.tcp_syncookies=1 # 永久生效 echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
同时调整半连接队列长度和超时时间:
sysctl -w net.ipv4.tcp_max_syn_backlog=2048 sysctl -w net.ipv4.tcp_synack_retries=1 sysctl -w net.ipv4.tcp_syn_retries=1
tcp_synack_retries 和 tcp_syn_retries 调小,意味着服务器对无响应的握手请求只重试一次就放弃,大幅缩短半连接占用的时间窗口,队列释放速度更快。
第二步:iptables限速,按源IP做SYN包速率控制
用iptables的 limit 模块可以快速实现单IP的SYN速率限制:
# 每秒最多允许3个SYN包,超过的丢包 iptables -A INPUT -p tcp --syn -m limit --limit 3/s --limit-burst 6 -j ACCEPT iptables -A INPUT -p tcp --syn -j DROP
这里 limit-burst 允许突发6个包,避免单个用户快速建立多个连接时被误伤,但这条规则对分布式攻击效果有限,因为攻击源IP分散,单IP速率可能并不高,如果想限制同一IP的并发半连接数,需要结合 recent 模块:
# 30秒内同一IP建立超过10次半连接,后续SYN直接丢弃 iptables -I INPUT -p tcp --syn -m recent --name synflood --rcheck --seconds 30 --hitcount 10 -j DROP iptables -A INPUT -p tcp --syn -m recent --name synflood --set -j ACCEPT
第三步:Nginx层限速,作为内核防护的第二道闸门
Web服务层也能做连接限速,Nginx的 limit_conn 和 limit_req 模块可以控制单IP的并发连接数和请求速率,但要注意,Nginx看到的已经是内核accept之后的连接,对于纯SYN Flood,Nginx层介入时连接已经建立完成,所以真正防御洪水还得靠内核层和防火墙层。
比较稳妥的做法是:内核算力兜底 + iptables规则粗筛 + Nginx应用层精确限速。
SYN Flood攻击如何验证,三步定位TCP异常握手来源
防护规则加上之后,怎么确认规则真的在生效、异常流量真的被打掉了?直接看数据。
用netstat和ss看半连接堆积
# 查看当前SYN_RECV状态的连接数量 ss -s netstat -ant | grep SYN_RECV | wc -l
正常情况下,SYN_RECV数量应该是个位数,如果持续几十上百,说明半连接队列异常堆积,SYN Cookie可能没有完全消化攻击流量,再看 /proc/net/stat/syncookies 的 SyncookiesSent 和 SyncookiesRecv 字段,前者远大于后者时,说明大量客户端没有回应三次握手的第三步,攻击特征非常明显。
抓包确认攻击特征
tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0' -c 100
如果抓到的SYN包源IP地址分布极分散,且TCP窗口大小、TTL值高度一致,基本可以判断是伪造源地址的攻击流量,如果源IP固定集中在一小段网段,则可能是真实IP发起的CC式TCP连接攻击,处理方法不同:后者直接封IP段更实用。
验证限速规则命中情况
# 查看iptables规则的匹配计数 iptables -L -v -n | grep synflood
规则匹配次数持续增长,说明攻击流量正在被拦截,如果计数不涨,说明流量走的路径不在这条规则链上,需要检查规则顺序和流量入口。
高防环境中TCP防护怎么配合,自建和高防该怎么选
如果业务已经接入高防IP,源站层面的TCP防护仍然不能省,但职责分工要清楚,高防机房通常在流量入站口做第一层清洗,把攻击流量稀释到源站可承受范围,源站的内核参数和iptables规则是兜底防线。
| 对比维度 | 自建机房防护 | 高防IP清洗 |
|---|---|---|
| 防护位置 | 源站服务器内核和防火墙 | 骨干网侧的流量清洗设备 |
| 处理能力 | 取决于服务器硬件和带宽 | 取决于高防机房的总带宽和集群规模 |
| 误杀风险 | 规则写紧容易误伤正常用户 | 清洗策略配置不当也会误杀 |
| 成本门槛 | 服务器加带宽成本,按月固定支出 | 按防御峰值计费,攻击期间费用明显上浮 |
高防IP的价格贵吗?这要看业务对可用性的要求,接入高防之后,TCP异常握手的验证逻辑也不冲突,高防清洗设备会把攻击流量过滤掉一大部分,到达源站的SYN速率会明显下降,源站的SYN Cookie和iptables规则能更从容地处理余量。
判断是否需要上高防,看一个指标:源站带宽和连接数是否有持续性冲击。 偶尔被打一次,自建防护加弹性带宽能扛过去,如果每周都被打,且攻击峰值超过源站带宽上限,那就不是调参能解决的问题了,该上高防就得上。
TCP异常握手防护的常见误区和优先级排序
误把tcp_max_syn_backlog调得很大当成防护手段,这是最典型的误区,队列再大也经不起持续高速填充,反而会因为队列过长拖慢正常连接的响应速度,优先级的正确排序应该是:
- 第一步保住协议栈:SYN Cookie开启是第一优先级,它让内核不分配资源就能完成握手验证。
- 第二步压住攻击源:iptables等防火墙工具的限速和黑名单机制,把明显异常的源IP挡在门外。
- 第三步扩容冗余:调大半连接队列、增加入口带宽,为正常用户的突发流量留余地。
- 第四步接入清洗网络:攻击规模超过单机能力时,借助高防基础设施吸收流量。
常见问题排查指南
开启SYN Cookie后正常用户访问变慢,是什么原因?
SYN Cookie本身不处理正常连接的建立效率,变慢更可能是iptables限速规则太严格,同一个NAT出口的多个用户共用了一个出口IP,被统一限速,建议将 limit-burst 值适当调大,或者配合 connlimit 模块按并发连接数而不是包速率做限制。
为什么抓包看到大量SYN重传,但服务器没有明显的连接堆积?
抓包位置在服务器网卡上,看到的是服务器发出的SYN-ACK在重传,这可能说明攻击者只发SYN不做响应,服务器的SYN-ACK发出后得不到ACK回应。tcp_synack_retries 如果保持默认的5次,每条半连接要等63秒才会释放,需要将重试次数调低,加速半连接回收,据工信部每年发布的网络安全态势报告,TCP洪泛攻击一直是政企网站遭遇最多的DDoS类型之一,所以这个调参动作值得提前做好。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/787156.html


