传输层协议TCP(5)

TCP 连接的初始序列号

       ISN(The Initial Sequence Number,ISN,初始序列号),就是创建 TCP 连接发送 SYN 报文时,其中的 SEQ(Sequence Number)的值。因为是初始创建连接时的请求报文,所以这个报文中的 SEQ,有一个特别的称号:初始序列号。关于 ISN 的取值,RFC 793 和 RFC 6528 都有专门论述,RFC 793的目的是为了防止网络残留报文所引发的混淆,RFC 6528 的目的是为了防止序列号的攻击。

1.1 防止网络残留报文的混淆

       标识1个 TCP 连接的是一个四元组:<本地 IP,本地端口,远端 IP,远端端口>(<local ip, lcoal port, remote ip, remote port>),但是这样的 TCP 连接是可以建了关、关了建的,如下图:

        

       TC1 与 TC2 没有任何区别,因为标识它们的四元组是一模一样的,都是:<IP1, Port1, IP2, Port2>。这样的话,就产生了1个问题,如下图5-74所示:

       

      在 t1 时刻,TC1 中的 A 给 B 发送了1个报文 SEG1。但是很不幸,这个报文直到 TC1 关闭,也没有到达 B,而是一直在网络中游荡。待到 TC2 创建了以后,t2 时刻,TC1 的 SEG1 才到达 B。为了更加能说明问题,我们继续在 t2 时刻之后的 t3 时刻加大“冲突”:t3 时刻,TC2 中的 A 给 B 发送的报文 SEG2 到达了。这样便会有如下问题:

  • 对于 TCP 来说,它根本分不出 TC1、TC2 是两个连接,因为两者的四元组是一样的;
  • 对于 TCP 来说,它更加无法知道 SEG1、SEG2 有何不同,因为两者的 SEQ 也是一样的。它只能知道,SEG2 是后来的,并且与 SEG1 重复,那就只能接受 SEG1,丢弃 SEG2。

      最终导致SEG2报文被丢弃了!我们把 SEG1 这样的报文——发自上一个 TCP 连接实例的报文,到达了新的 TCP 连接实例——称为网络残留报文。

      RFC 793 给出的算法,简单地说就是:ISN 每4毫秒加1。RFC 793 没有给出 ISN 自身的初值应该等于多少,我们就假设 TCP 启动时,ISN 自己初值等于0吧,这不重要。按照 RFC 793 给出的算法,TCP 创建1个连接时,它的 SYN 报文的 SEQ(也就是 ISN)的取值,如图5-75所示:

      

       上图5-75中,T0 就是 A 的 TCP 进程启动的那一刻,此时 ISN = 0。以后,每隔4ms,ISN 加1。待到 A 要与 B 创建 TCP 连接发送 SYN 请求时,此时 ISN 等于几,那么该 SYN 报文的 SEQ(也就是这个连接的 ISN)就等于几。由于 ISN(也就是 SEQ)是一个32 bits 的无符号整数,从0开始,每4毫秒加1,那么差不多4.55小时后,ISN 会翻转到0。这样的算法,能解决“网络残留报文”所带来的混淆吗?我们看图5-76:

        

       TCP只能根据报文本身的参数来判断报文的合法性。关于合法性的判断,前面章节讲了很多,这里就不再啰嗦,这里只提一点:关于所接收报文 S/L 的判断。这里只重复介绍两个公式。只要满足如下两个公式之一,报文就是合法的:

  • (1)RCV.NXT <= SEG.SEQ + SEG.LEN - 1 < RCV.NXT + RCV.WND
  • (2)RCV.NXT <= SEG.SEQ < RCV.NXT + RCV.WND

       报文是否合法,只与当前报文的 SEG.SEQ、SEG.LEN 以及当前接收方的 RCV.NXT、RCV.WND 这4个参数有关。而这4个参数,与所谓 TCP 连接的 ISN 根本没有必然的因果关系。那么,什么能消除网络残留报文的影响呢?答案是时间!

        

      上图5-77中,极端情况下,t1 和 t2 的时间间隔是0,也就是说在 t1 时刻,A 发送了报文 SEG1 以后,该 TCP 连接就关闭了。极端情况下,t3 和 t4 之间的时间间隔也是0,也就是说,t3 时刻点一到,马上就创建一个新的 TCP 连接。t3 与 t2 之间的时间间隔 Δt = MSL,MSL 是 Maximum Segment Lifetime 的缩写,其含义是:一个报文在网络中最大存活时间。这是一个经验数值,RFC 793建议是2分钟,您也可以设置您的经验值,比如1分钟,比如5分钟。

       由此,我们知道 t3 的时刻点的含义是:当1个 TCP 连接关闭时,只要我们等待 MSL 时间以后再重新建立新的 TCP 连接,那么网络残留报文肯定不会存在了,也就说,网络残留报文的问题解决了!

       对于具体的实现来说,可以做多种选择:

    (1)如果上次关闭是正常关闭,那本次创建 TCP连接时,就可以不必等待,直接设置“本次.ISN = 上一次.SEQ + 1”;

    (2)如果上次关闭是异常关闭,

  • (A)那或者是等待 MSL 再创建新的连接,这样可以避免“网络残留报文”的风险
  • (B)或者是不等待,直接创建新的连接,但是要承担“网络残留报文”的风险

       无论做何种选择,笔者还是想强调的是,“网络残留报文”的风险与 RFC 793 所推荐的 ISN 取值算法无关,该算法既不能降低风险,也不会提高风险。不过,ISN 的这种算法,却很不幸地引入了另外一个问题:序列号攻击。

1.2 防止序列号攻击

       对于 RFC 6528(替代了 RFC 1948) 来说,序列号攻击有着特定的含义,首先它指的是“旁路攻击(off-path attack)”,而不是“中间人攻击(man-in-the-middle attack)”,如下图5-78所示:

        

       另外,即使是旁路攻击,RFC 6528 也强调它的方法不是解决攻击的根本之道——根本之道是安全加固——但是考虑到网络中有些协议和实现,短期内不太可能都去“加固”其安全,所以该方法在一定的场景下,还是有比较大的作用。 这个“一定的场景”,就是 RFC 6528 所说的“序列号攻击”的第2个含义,如图5-79所示:

       

       上图5-79中的被攻击对象 C 和它的信任对象 B 之间的通信协议是 TCP,C 与 B 之间的安全措施有:(1)用户名/密码;(2)C 的配置文件中所配置的信任列表(IP 地址列表,白名单)。但是,由于 C-B 之间的通信协议是 TCP,所以 A-B 之间的通信协议也得是 TCP,那么问题来了:A 可以仿冒 B 的 IP 地址,A 又该如何知道 B-C 之间 TCP通信报文的 SEQ 呢?如图5-80所示:

        

        A 仿冒 B,跟 C 进行 TCP 通信,那么通信的前提就是 A(仿冒 B)先和 C 建立 TCP 连接,否则一切免谈。图5-80所描述的就是经典的“三次握手”,我们将之以下表格的形式再描述一下:

        

        A想要(仿冒 B)先和 C 建立 TCP 连接,需要知道“第二次握手”中 C 的 ACK/SYN 报文的 SEQ,否则无法建立TCP连接。然而,吊诡的是,RFC 793 所介绍的 ISN 计算方法,不仅没有解决“网络残留报文混淆”的问题,反而还给旁路攻击提供了可乘之机,如图5-81所示:

        

       上图5-81描述的是这样的过程:

  • (1)A 正常做自己(不仿冒 B),与 C 所在 Host 上的另一个 TCP 服务 D,建立 TCP 连接。因为 D 不需要地址认证,所以 A 能与 D 进行正常的三次握手。在三次握手过程中,A 知道的 D 的 ISN,即 ISNd。
  • (2)A 再仿冒 B,与 C 建立 TCP 连接。如前文所述,在第三次握手时,B 需要猜测 C 的 ISN,即 ISNc。
  • (3)只要 A 知道 D 与之第二次握手的时间 t1(这个肯定知道),同时也知道 C 与 B 的第二次握手的时间 t2(这个需要猜测,但是比较容易猜测),那么就可以通过 ISNd 推导出 ISNc:ISNc = ISNd + (t2 - t1)/4

       虽然,在同一个 Host 上,除了被攻击对象 C,还需要一个普通的 TCP 服务 D,而且还需要猜测 t2 时间点,好像这些条件比较苛刻,但是从世界范围内来看,这种利用猜测 TCP 序列号来进行旁路攻击的情形还是很多。

        RFC 6528(RFC 1948)提出了一种算法,来解决这种旁路攻击。看图5-81,攻击者 A 之所以能猜测出 C 的 ISN,最根本的原因是:一个 Host 内,所有的 TCP 连接共享一个 ISN 计算空间:ISN = ISN0 + (t - t0)/4。正是由于这个原因,攻击者 A 才能够通过 D 的 ISNd 猜测出 C 的 ISNc。RFC 6528 提出的算法,正是针对此漏洞进行弥补,它的算法是:

         ISN = ISN793 + F(local ip, lcoal port, remote ip, remote port)

       公式中,ISN793 就是 RFC 793所介绍的算法(ISN = ISN0 + (t - t0)/4)。公式中,F(local ip, lcoal port, remote ip, remote port),其中 F 是一个密码哈希函数,比如 MD5。可以看到,F 函数实际上是1个针对每个 TCP 连接都不相同的随机加密数。ISN 就变成了:

         ISN = ISN0 + (t - t0)/4 + F(四元组)

       按照这样的公式,显然,攻击者 A 就无法通过 ISNd 推导出 ISNc 了。当然,如果通过其他手段攻破 F,那是另外的话题了,与本节无关。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值