回答重点
初始序列号 ISN 是以时间戳为基础生成的。
RFC793 中认为 ISN 要和一个假的时钟绑定在一起。ISN 每四微秒加一,当超过 2 的 32 次方之后又从 0 开始,即四个半小时左右发生 ISN 回绕。
所以 ISN 变成一个递增值,真实的实现还需要加一些随机值在里面,防止被不法份子猜到 ISN。
扩展知识
为什么初始序列号不能写死,比如从 0 开始?
想象一下如果写死一个值,比如 0 ,那么假设已经建立好连接了,client 也发了很多包比如已经第 20 个包了,然后网络断了之后 client 重新,端口号还是之前那个,然后序列号又从 0 开始,此时服务端返回第 20 个包的 ack,客户端是不是错乱了?
所以它基于时间递增比较合适,并且还提高了安全性,避免不法分子预测序列号。
小结下为什么这样设计:
- 避免重复序列号导致的冲突:如果两个连接在短时间内使用了相同的 ISN,可能会导致数据包被错误地认为是属于前一次连接的,从而引发数据错误。动态生成 ISN 可以有效避免这种冲突。
- 提高安全性:动态的 ISN 使得预测或篡改 TCP 序列号变得困难,从而提高了连接的安全性,抵御诸如 TCP 序列号预测攻击。
RFC 6528
RFC 6528 提出了安全改进,用于增强 TCP 初始序列号 (ISN) 的生成,以抵御序列号预测攻击。
可以看到,M 是每 4 微秒 1 的计时器,F 是一个伪随机函数,可以基于 MD5 将源IP、源端口、远端ip、远端端口和一个密钥生成一个哈希值,以抵御序列号预测攻击。