摘要

  • RFC 1948 描述的攻击者先从正常连接取样,再冒用受信任主机的 IP 地址,猜服务器给伪造连接分配的起始序列号,完成一场看不到服务器回信的握手。
  • 它保留为同一连接身份持续前进的时间量 M,为每组本地与远端地址、端口加入秘密偏移 F。从一条连接读到的号码,不再提供下一条连接的起点地图。

小偷先规规矩矩地敲门:建立一条真正的 TCP 连接,记下服务器抛出的起始号码。1996 年 5 月的 RFC 1948解释了下一步。他冒用服务器信任的另一台主机地址;服务器的回答发向真正的主机,小偷看不到。只要把那台主机暂时堵住,并猜中服务器即将使用的号码,小偷仍能补上最后一个确认。若远程命令服务把 IP 地址当作信任凭据,伪造者便以熟人的身份进了门。

破绽藏在两场对话之间。第一次正常连接泄露一个初始序列号,即 ISN。RFC 1948 描述的 Berkeley 系统衍生实现,会按时间和新连接次数用可预测的幅度增加号码。伪造连接需要服务器的下一个 ISN;从样本推得这个数,攻击者便可在看不到服务器回信的情况下完成握手。柜台把下一张票的号码念得太大声。

随手为每条新连接掷一次骰子,听起来简单。最初的 TCP 规范 RFC 793却让初始号码随着时钟前进,使同一组端点重新连接时,上一轮滞留的旧包不容易冒充新包。RFC 1948 还提到 BSD 系统对 TIME-WAIT 状态的处理。不同连接需要互不相干的起点;同一连接身份的多次开张仍要有向前推进的顺序。两种要求挤在同一个 32 位字段里。

RFC 1948 把它们拆开。一条 TCP 连接由四项标识:本地 IP、端口,远端 IP、端口。提案把初始号码写成 M + F(四元组)。M 是前进的计时器;F 是四元组与秘密材料计算出的偏移。每组四元组有自己的号码跑道,重复使用同一组端点时,时钟继续把起点向前推。看过一条跑道上的票,仍不知道隔壁从哪里开始。

秘密必须藏得住。RFC 1948 建议对四元组和秘密材料使用密码学哈希,并以当时容易取得的 MD5 为例。文中讨论随机数、主机自己的秘密、开机时间以及机器身份的组合。若外人算得出 F,隔壁柜台的票号仍可预测。这个办法也省去了为所有已经结束的连接永久保留状态的负担。

换钥匙则有代价。机器运行中改变秘密,会移动某组四元组重开连接时的号码跑道;旧包可能还没离开网络。RFC 1948 因此要求保留已结束连接的状态,或者在换钥匙后安静等待两个最大报文存活期。秘密把不同跑道隔开,时间给同一跑道的多次使用留出距离。转动新锁前,还得看门缝里有没有上次留下的东西。

2012 年的 RFC 6528把这套方法提升为标准轨道,取代 RFC 1948,并更新 RFC 793。它更明确地规定四元组与秘密密钥驱动的伪随机函数,保留 M + F 结构,也讨论密钥长度和轮换。1996 年的关键动作延续下来:时间负责同一连接身份的先后,秘密负责切断不同连接身份之间的可预测联系。

小偷照样可以排队领一张票。RFC 1948 拿走的是从这张票推算另一扇门起跑线的尺子。下一道门背后的偏移,留在柜台里面。