1. 握手协议基础:TCP三次握手原理、SYN洪泛攻击与防护、握手超时与重传机制
说到网络安全,TCP握手协议是绕不开的第一道门槛。我做了这么多年安全防护,见过太多攻击都是从握手阶段入手的。说白了,三次握手就像两个人打电话确认对方能听见——但总有人想在这环节搞破坏。
1.1 三次握手:建立连接的标准流程
TCP是面向连接的协议,通信前必须先建立连接。三次握手就是干这个的。我习惯把它理解成一次「双向确认」的过程。
核心流程:
- 客户端 → 服务端:SYN — 客户端说「我想跟你说话」,同时带上自己的初始序列号(ISN)。
- 服务端 → 客户端:SYN+ACK — 服务端回复「收到,我也准备好了」,带上自己的ISN,同时确认客户端的ISN。
- 客户端 → 服务端:ACK — 客户端最后确认「好的,开始通信」。连接建立完成。
你想想看,为什么非得三次?两次行不行?我遇到过刚入行的同事问这个问题。其实很简单:两次握手无法防止「已失效的连接请求」突然到达服务端。三次握手通过最后一次ACK,让服务端确认客户端确实还活着。
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洪泛被打垮,或者因为超时配置不合理导致用户体验极差。把这些基础打牢,后面的数据传输才能安全可靠。