1. 握手协议基础:TCP三次握手原理、SYN洪泛攻击与防护、握手超时与重传机制

说到网络安全,TCP握手协议是绕不开的第一道门槛。我做了这么多年安全防护,见过太多攻击都是从握手阶段入手的。说白了,三次握手就像两个人打电话确认对方能听见——但总有人想在这环节搞破坏。

1.1 三次握手:建立连接的标准流程

TCP是面向连接的协议,通信前必须先建立连接。三次握手就是干这个的。我习惯把它理解成一次「双向确认」的过程。

核心流程:

  1. 客户端 → 服务端:SYN — 客户端说「我想跟你说话」,同时带上自己的初始序列号(ISN)。
  2. 服务端 → 客户端:SYN+ACK — 服务端回复「收到,我也准备好了」,带上自己的ISN,同时确认客户端的ISN。
  3. 客户端 → 服务端:ACK — 客户端最后确认「好的,开始通信」。连接建立完成。

你想想看,为什么非得三次?两次行不行?我遇到过刚入行的同事问这个问题。其实很简单:两次握手无法防止「已失效的连接请求」突然到达服务端。三次握手通过最后一次ACK,让服务端确认客户端确实还活着。

TCP三次握手流程图 客户端 服务端 CLOSED → SYN_SENT LISTEN → SYN_RCVD ① SYN (seq=x) ② SYN+ACK (seq=y, ack=x+1) ③ ACK (seq=x+1, ack=y+1) ESTABLISHED ESTABLISHED 连接建立,开始数据传输

1.2 SYN洪泛攻击:握手阶段的致命漏洞

三次握手有个天然缺陷——服务端在收到SYN后,会分配资源并进入SYN_RCVD状态,等待客户端的ACK。如果客户端不发ACK呢?

这就是SYN洪泛攻击的原理。攻击者伪造大量源IP,疯狂发送SYN包,但从不完成第三次握手。服务端的半连接队列很快被填满,正常用户再也连不上。

我曾经在客户现场遇到过这种情况:某电商平台大促前突然瘫痪,TCP连接全部超时。检查后发现半连接队列爆满,正常SYN根本进不去。攻击者只用了不到100Mbps的流量,就把一台64G内存的服务器打趴了。

对比项 正常连接 SYN洪泛攻击
源IP真实性 真实可达 伪造/随机
三次握手完成 是 否(停留在半连接)
服务端资源消耗 低(连接建立后释放) 高(队列被占满)
对正常用户影响 无 连接超时/拒绝服务

1.3 防护手段:让攻击者无处下手

对付SYN洪泛,我总结了几种有效手段。嗯,这里要注意——没有银弹,得组合使用。

我个人最推荐的组合:

  • SYN Cookie:收到SYN时不分配资源,而是用Cookie编码连接信息。ACK到达时验证Cookie,合法才分配资源。Linux内核默认开启,但会禁用TCP时间戳等高级特性。
  • 缩短超时时间:把SYN_RCVD超时从默认的60秒降到5-10秒。攻击者填队列的速度会变慢。
  • 限制半连接数量:用iptables或防火墙限制单IP的半连接数。我习惯设为100,超过就丢包。
# Linux内核参数调优示例
# 开启SYN Cookie
echo 1 > /proc/sys/net/ipv4/tcp_syncookies

# 缩短SYN_RCVD超时(单位:秒)
echo 5 > /proc/sys/net/ipv4/tcp_synack_retries

# 限制半连接队列最大长度
echo 1024 > /proc/sys/net/ipv4/tcp_max_syn_backlog

# 用iptables限制单IP半连接数
iptables -A INPUT -p tcp --syn -m connlimit --connlimit-above 100 -j DROP

1.4 握手超时与重传机制:网络不靠谱时的保命手段

网络环境没那么理想。丢包、延迟、乱序,都会导致握手失败。TCP的重传机制就是干这个的。

我遇到过最典型的场景:跨洋链路延迟200ms,客户端发SYN后等不到SYN+ACK,就会重传。默认重传次数是5次,每次超时时间翻倍(1s、2s、4s、8s、16s),总共等31秒才放弃。

重传时间计算(RTO):

  • 初始RTO:1秒(很多系统实际用3秒)
  • 每次重传:RTO × 2(指数退避)
  • 最大重传次数:5次(Linux默认)
  • 总等待时间:约31秒(1+2+4+8+16)

为什么会设计指数退避?你想想看,如果网络已经拥塞了,你还拼命重传,只会让情况更糟。退避是给网络喘息的时间。

避坑指南:我曾经把重传次数改成10次,想着「多等一会儿总比连不上好」。结果客户端卡了3分钟才报超时,用户早就跑了。实际场景中,5次重传已经够用。如果31秒还连不上,说明网络确实有问题,不如早点失败让应用层处理。

1.5 实战建议:从配置到监控

说了这么多,最后给几条落地建议:

  • 生产环境一定要开SYN Cookie。性能损失几乎可以忽略,但能防住大部分SYN洪泛。
  • 监控半连接队列水位。用ss -s或netstat -s看半连接数量。如果持续超过队列长度的70%,就该报警了。
  • 根据业务场景调整超时。内网通信可以缩短超时,跨公网可以适当放宽。
  • 别忽略应用层超时。TCP重传只是底层保障,应用层也要设超时,防止线程被长时间挂起。

握手协议看起来简单,但里面坑不少。我见过太多系统上线后因为SYN洪泛被打垮,或者因为超时配置不合理导致用户体验极差。把这些基础打牢,后面的数据传输才能安全可靠。