摘要

  • TCP 三次握手不是数据传输前的礼节。它最初的主要目的,是避免一份迟到的旧 SYN 被当成当前连接请求。
  • 每个端点各自选择初始序号。应答方可以把“我已看见你的序号”和“这是我的序号”合并进一个 SYN-ACK,但发起方必须再回一个 ACK,才能证明它收到的是这一次挑战。
  • 静默期、TIME-WAIT、带秘密偏移的 ISN 与 SYN Cookie 分别处理旧数据、序号猜测和过早占用服务器资源;它们都不等于身份认证。

来自上一段对话的包

互联网会延迟、复制并乱序传送数据。因而,“包到了”不等于“包仍然有效”。一条 TCP 连接关闭后,两个应用可能很快重用相同的源地址、源端口、目的地址与目的端口;上一条连接的 SYN 或数据仍可能在网络中游荡。

接收端看到熟悉的四元组和 SYN 标志,却无法从包本身读出年代。若它把这一份 SYN 当作足够证据,过期请求就可能制造当前状态。

1980 年 1 月的 RFC 761 把问题放进序号空间:两端各自选择初始发送序号,并在建连阶段学习对方的选择。序号能帮助后续数据排序和去重,但前提是先确定这一轮连接究竟从哪里开始。

三个包承载四个事实

同步其实需要四句话:A 告诉 B“我的序号从 X 开始”;B 确认 X;B 告诉 A“我的序号从 Y 开始”;A 再确认 Y。

TCP 把中间两句合并。第一包是 SYN X,第二包是 SYN Y, ACK X+1,第三包是 ACK Y+1。所以逻辑上有四次陈述,线上只需三次传递。

加一不是装饰。SYN 本身占用一个序号位置,因此对方期待 X+1;纯 ACK 不占序号,否则确认还要被再次确认,形成无穷链。1981 年 9 月的 RFC 793 把这套交换写入标准 TCP 状态机。

没有中央连接登记簿,也没有一座为全球 TCP 分配序号的时钟。两端各做本地选择,再用消息把选择变成双方可验证的共同状态。

第三次才是发起方的证明

如果收到 SYN-ACK 就结束,看上去双方都已知道彼此。但对应答方 B 而言,它只知道自己见过 A 的一份 SYN;它不知道 A 是否现在仍记得这份请求。那可能是上一轮连接留下的复制包。

最后一个 ACK 补上这一缺口。它证明当前掌握 A 端状态的一方看见了 B 的 Y,并返回正确确认。RFC 761 把三次握手称为“记忆与消息之间的取舍”:当接收端不可能保存每一对端点历次使用过的全部序号时,就多发一条消息,让表面上的发起者验证当前交换。

这种证明很窄。它证明当前 TCP 状态收到了序号挑战,不证明操作者是谁,不授权应用交易,也挡不住能旁观和改写路径流量的攻击者。

旧包不只需要编号,也需要时间

握手解决连接发起时的旧 SYN,连接关闭后仍有旧数据风险。TCP 因而把序号与时间一起使用:只要携带某序号的包仍可能存在,该序号就没有完全恢复为“空闲”。

早期规范把最大报文生存期 MSL 假定为两分钟。主机若崩溃并丢失近期序号记忆,重启后应静默一个 MSL;若记忆仍在,则可以从已用范围之外继续。

正常关闭后,TIME-WAIT 保留四元组两个 MSL。它既让迟到包耗尽,也允许最后的关闭确认重传。等待不是多余流程,而是防止旧证据获得新含义的一段状态。

当前基础规范 RFC 9293 保留这一模型,同时指出现代实现通常不必真的执行重启静默期:临时端口与 ISN 随机化降低重用概率,包在网络中的有效寿命缩短,重启本身往往已超过危险窗口;高速链路则依靠时间戳与 PAWS 防止序号快速绕回。原则没变,常用工具变了。

TIME-WAIT 也会忘记职责

时间保护只有在实现保留它时才有效。RFC 1337 描述了“TIME-WAIT 暗杀”:旧包抵达后诱发 ACK,而已删除连接状态的对端返回 RST;如果这一 RST 被接受,TIME-WAIT 会提前结束。

同一个四元组马上重开时,旧数据或旧 ACK 可能落进新窗口。文档给出了错误接收数据、双方序号失同步和新连接失败等情形。这并不否定三次握手,而是说明不同机制各守一段边界:握手排除旧 SYN,活动连接的窗口检查排除不合序号的包,TIME-WAIT 隔开前后两次连接。

把互补保护当成重复优化掉,歧义就会重新进入系统。

新鲜序号不是已认证身份

早期规范已经明说,防旧重复包的策略并不防欺骗。若攻击者能预测服务器下一个初始序号,就可能在看不见回复时伪造对方期待的确认。

RFC 6528 加固了 ISN:把计时器与一个使用本地地址、远端地址、双方端口和秘密值的伪随机函数相加。不同四元组得到没有明显外部关系的序号空间,同时保留随时间前进的性质。

它保护的是有限命题:离路径攻击者更难猜中可接受的序号。路径上的观察者仍能看到交换。若系统要确认“对方是谁”,还要在 TCP 之上或传输层内使用密码认证。

把未分配的状态装进挑战

握手还暴露一种资源不对称。开放服务器收到第一份 SYN 后,可能先为半连接分配控制块;伪造者无需完成握手,只要不断发送 SYN,就能塞满队列。

RFC 4987 记录了 SYN Flood 在 1996 年公开并造成运营影响的历史。SYN Cookie 的办法不是取消第三次确认,而是推迟内存承诺:服务器用客户端四元组、客户端序号、时间、少量协商参数和秘密函数构造 SYN-ACK 的序号;最终 ACK 返回时,才验证并重建足够状态。

这相当于把一份紧凑承诺塞进挑战本身。证据回来之前,服务器不必为每个声明保留完整记忆。位数有限会影响某些 TCP 选项,具体算法也并不唯一,所以它不是无代价的魔法。

这段历史真正讲的并非“三个包如何打开 TCP”,而是互联网怎样把若干不同权力拆开:网络只负责转发声明;端点各选序号;相互确认把本地选择变成共享状态;时间限制旧包的意义;秘密降低盲猜;延迟分配限制无人回应的成本。没有一项需要升级成全球会话权威,也没有一项能证明自己观察范围以外的身份或正当性。

来源与证据边界

RFC 能证明规范内容、设计理由和部分失败分析,不能给出所有 TCP 实现的统一部署日期。本文所说“本地选择经相互证据成为共享状态”是对机制的架构解读,不是 RFC 使用的原词。