5.2.13 TCP 连接的初始序列号

在前文中,一直提到一个词 ISN(The Initial Sequence Number,ISN,初始序列号),就是创建 TCP 连接发送 SYN 报文时,其中的 SEQ(Sequence Number)的值。因为是初始创建连接时的请求报文,所以这个报文中的 SEQ,有一个特别的称号:初始序列号。

关于 ISN 的取值,RFC 793 和 RFC 6528 都有专门论述,甚至 RFC 6528 整篇文档都是为了讲述 ISN,这足以见得 ISN 的重要性。两篇 RFC 所讲述的 ISN 取值算法,RFC 793的目的是为了防止网络残留报文所引发的混淆,RFC 6528 的目的是为了防止序列号的攻击。

下面我们就分别讲述这两种算法。

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

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

图5-73 TCP 连接的多次创建与关闭

图5-73中,人类的视角可以知道那是两个 TCP 连接:TC1、TC2(TC: TCP Connection,TCP 连接)。但是从 TCP 的视角来看,TC1 与 TC2 没有任何区别,因为标识它们的四元组是一模一样的,都是:<IP1, Port1, IP2, Port2>。这样的话,就产生了1个问题,如图5-74所示:

图5-74 网络残留报文

图5-74中,从人类的视角来看,这是两个连接 TC1、TC2。在 t1 时刻,TC1 中的 A 给 B 发送了1个报文 SEG1。但是很不幸,这个报文直到 TC1 关闭,也没有到达 B,而是一直在网络中游荡。

待到 TC2 创建了以后,t2 时刻,TC1 的 SEG1 才到达 B。为了更加能说明问题,我们继续在 t2 时刻之后的 t3 时刻加大“冲突”:t3 时刻,TC2 中的 A 给 B 发送的报文 SEG2 到达了。而且单独看报文本身,两者根本看不出区别:四元组一样,SEG 也一样。

有人可能会说,两者的数据长度不一样(SEG1.DataLen = 20,SEG2.DataLen = 30),以及它们所承载的数据也不一样。但是这没有意义:

(1)对于人来说,他能知道 TC1、TC2 是两个连接,SEG1、SEG2 分属 TC1、TC2,它们是两个报文

(2)对于 TCP 来说,它根本分不出 TC1、TC2 是两个连接,因为两者的四元组是一样的

(3)对于 TCP 来说,它更加无法知道 SEG1、SEG2 有何不同,因为两者的 SEQ 也是一样的。它只能知道,SEG2 是后来的,并且与 SEG1 重复,那就只能接受 SEG1,丢弃 SEG2。

我们把 SEG1 这样的报文——从人类的视角而言,发自上一个 TCP 连接实例的报文,到达了新的 TCP 连接实例——称为网络残留报文。

由来自有新人笑,有谁听到旧人哭?人类的世界里,旧人的哭,让人无奈、让人同情、让人感慨......但是在 TCP 的世界里,来自上一个连接实例的报文,只能让 TCP“痛不欲生”,因为它实在区分不出:哪一个是现实,哪一个是旧梦!

很多资料都说 ISN 的取值算法(就是 RFC 793 所描述的算法),能够帮助 TCP 解决这个问题。甚至 RFC 793,也在有意无意地暗示它能解决这个问题:

"how does the TCP identify duplicate segments from previous incarnations of the connection?"

To avoid confusion we must prevent segments from one incarnation of a connection from being used while the same sequence numbers may still be present in the network from an earlier incarnation.......When new connections are created,an initial sequence number (ISN) generator is employed which selects a new 32 bit ISN.  The generator is bound to a (possibly fictitious) 32 bit clock whose low order bit is incremented roughly every 4 microseconds.  

RFC 793 给出的算法,简单地说就是:ISN 每4毫秒加1。RFC 793 没有给出 ISN 自身的初值应该等于多少,我们就假设 TCP 启动时,ISN 自己初值等于0吧,这不重要。

按照 RFC 793 给出的算法,TCP 创建1个连接时,它的 SYN 报文的 SEQ(也就是 ISN)的取值,如图5-75所示:

图5-75 ISN 的算法

图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。这没有关系,该翻转就翻转。

每4毫秒加1也好,4.55小时翻转1次也罢,这都不是重点。重点是:这样的算法,能解决“网络残留报文”所带来的混淆吗?我们看图5-76:

5-76 网络残留报文的合法性

前文说了,TCP 根本没法知道它所接收的报文是不是网络残留报文,它只能根据报文本身的参数来判断报文的合法性。关于合法性的判断,5.2.12节讲了很多,这里就不再啰嗦,这里只提一点:关于所接收报文 S/L 的判断。详细的判读细节,请参见“5.2.12.2节的‘2) 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 根本没有必然的因果关系:不是说只要创建 TCP 连接时,该连接的 ISN 取了什么样的一个值,就能使得网络残留报文变得不合法(或者变得合法)。

无论 ISN 取何值,网络残留报文都有可能合法(或者不合法)。也就是说,要想消除网络残留报文的影响,与 ISN 的取值无关——多么痛的领悟!

那么,什么能消除网络残留报文的影响呢?时间!只有时间才能治愈爱的酸楚!如图5-77所示:

图5-77 网络残留报文的清除

图5-77中,极端情况下,t1 和 t2 的时间间隔是0,也就是说在 t1 时刻,A 发送了报文 SEG1 以后,该 TCP 连接就关闭了。极端情况下,t3 和 t4 之间的时间间隔也是0,也就是说,t3 时刻点一到,马上就创建一个新的 TCP 连接。

问题的重点是:t3 是一个说明时刻点?t3 和 t2 是说明关系?

图5-77中,t3 与 t2 之间的时间间隔 Δt = MSL,MSL 是 Maximum Segment Lifetime 的缩写,其含义是:一个报文在网络中最大存活时间。

我们知道,每个 IP 报文都有 TTL 字段,TTL 最大值是255,也就是说1个 IP 报文,最多在网络中被传输了255跳,然后就要被网络(路由器)丢弃了。255跳大概相当于多少时间呢?这是一个经验数值,RFC 793建议是2分钟,您也可以设置您的经验值,比如1分钟,比如5分钟。

具体等于多少不重要,重要的是两点:(1)肯定有这么1个值 MSL;(2)MSL 不会太长(最多是分钟级)。

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

让时间来解决,充满了哲学意味,但是从某种意义上讲,也有一定的讽刺意味——那说好的算法呢?原来所谓的算法,就是傻等!人类的智慧呢?TCP 如果可以感慨,不知道会不会觉得:人类不值得!

当然,如果 TCP 能够知道上一次 TCP 关闭时的 SEQ,那么这一次创建连接时,只需要将本次的 ISN 设置为上次的 SEQ 加1即可: 本次.ISN = 上一次.SEQ + 1。

但是,我们不能做这样的假设,因为 TCP 的关闭,可能是正常关闭(此时可以记录关闭时的 SEQ),也可能是异常关闭,比如程序异常退出(此时根本来不及记录关闭时的 SEQ)。

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

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

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

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

(B)或者是不等待,直接创建新的连接,但是要承担“网络残留报文”的风险

无论做何种选择,笔者还是想强调的是,“网络残留报文”的风险与 RFC 793 所推荐的 ISN 取值算法无关,该算法既不能降低风险,也不会提高风险。

不过,ISN 的这种算法,却很不幸地引入了另外一个问题:序列号攻击。

5.2.13.2 防止序列号攻击

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

图5-78 旁路攻击与中间人攻击

由于文章主题的原因,本文不对两种攻击做介绍,不过图5-78应该较形象地说明了两种攻击的特点。需要强调的是,RFC 6528 所介绍的算法,解决不了中间人攻击的问题。

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

这个“一定的场景”,就是 RFC 6528 所说的“序列号攻击”的第2个含义,如图5-79所示:

图5-79 序列号攻击示意

图5-79中的被攻击对象 C 和它的信任对象 B 之间的通信协议是 TCP,C 与 B 之间的安全措施有:(1)用户名/密码;(2)C 的配置文件中所配置的信任列表(IP 地址列表)。也就说,即使 A 通过某种手段知道了用户名/密码,但是由于它的 IP 地址不在 C 的信任范围内,C 也不会接纳它。这就是所谓的“基于地址的认证”。对于 A 来说,它要攻击 C 的第1步就是仿冒 B 的 IP 地址。

但是,由于 C-B 之间的通信协议是 TCP,所以 A-B 之间的通信协议也得是 TCP,否则别说是攻击了,连网络都通不了。既然是 TCP,那么问题来了:A 可以仿冒 B 的 IP 地址,A 又该如何知道 B-C 之间 TCP通信报文的 SEQ 呢?如图5-80所示:

图5-80 SEQ/AKN 的重要性

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

表5-27  仿冒场景的三次握手

报文

发送者

接收者

报文源 IP

报文

目的 IP

报文格式

说明

SEG1

A

C

B.IP

C.IP

SYN,

SEQ = ISNx

第一次握手。

A 冒充 B,给 C 发送 SYN 报文,A 的 SEQ = ISNx

SEG2

C

B

C.IP

B.IP

SYN/ACK,

EQ = ISNc,

AKN = ISNx + 1

第二次握手。

C 给 B 回以 ACK,同时包含 SYN。C 的 SEQ = ISNc

SEG3

A

C

B.IP

B.IP

ACK,

SEQ = ISNx + 1,

AKN = ?

第三次握手。

A 并没有收到 C 发送的 ACK/SYN 报文,但是还得冒充 B 给 C 回以 ACK 报文。但是 A 如何知道 C 的 ACK/SYN 报文的 SEQ,它的 AKN 该等于多少?这是 A 面临的最大的问题!!!

正如表5-27所说的,A 固然可以伪装成 B,试图与 C 建立 TCP 连接,但是当建立连接进入到“第三次握手”时,A 如何知道“第二次握手”中 C 的 ACK/SYN 报文的 SEQ?如果不知道,那么 A 就没法正确设置“第三次握手”报文中的 AKN 字段——没法正确设置,就会握手失败。也就说,创建连接失败,A 试图伪装成 B 对 C 进行的攻击,以失败告终。

然而,吊诡的是,RFC 793 所介绍的 ISN 计算方法,不仅没有解决“网络残留报文混淆”的问题,反而还给旁路攻击提供了可乘之机,如图5-81所示:

图5-81 利用 ISN 算法猜测对方的 ISN

图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(四元组)

假设采用这种算法,我们再次回图5-81中的 ISNd 和 ISNc:

ISNd = ISN0 + (t1 - t0)/4 + F(d.ip, d.port, a.ip, a.port)

ISNc = ISN0 + (t2 - t0)/4 + F(c.ip, c.port, b.ip, b.port)

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

人生若只如初见,何事秋风悲画扇。笔者以为,如果不是 RFC 793 给出了那样一个 ISN 的算法,也就不会有后面的故事,也不需要有后面的故事......

灯火阑珊的街头

寂寞如雪的酒

擦肩而过的回眸

转角还会不会再有

传输层协议(6):TCP 连接(下-3)相关推荐

  1. TCP/IP传输层协议实现 - TCP连接的建立与终止(lwip)

    1.lwip tcp相关数据结构 1.1.tcp报文格式 <TCP-IP详解卷 1:协议>TCP包首部结构如下: 1.2.lwip tcp数据结构 tcp相关数据结构如下,tcp_pcb_ ...

  2. 传输层协议(TCP/UDP)介绍

    一,TCP/IP协议族的传输层协议概况:  1,TCP:传输控制协议  2,UDP:用户数据报协议  二,TCP/UDP协议详解:  1,TCP  a.TCP是面向连接的,可靠的进程到进程通信的协议 ...

  3. Linux网络编程(传输层协议 )—tcp三次握手/四次挥手

    传输层协议:负责应用程序之间数据传输-TCP/UDP UDP协议: 16位源端-对端端口:用于描述识别通信两端进程 16位数据报长度:能够存储最大数字 65535,(udp报文总大小不超过64k) 1 ...

  4. 传输层协议之TCP协议详解

    传输层重点协议:UDP和TCP. 作用:负责数据能够从发送端传输到接收端.(在进行网络编程时,我们会使用到socket,然而一旦调用socket就进入到了传输层的范畴内) 前面我们已经讲过UDP协议了 ...

  5. OSI七层协议与TCP连接

    概述 为了追求效率,我们写代码,不可能去关注底层知识,但往往到出了问题,或者性能调优.我们就会速手无策,仔细为自己查缺补漏,总结知识点. 网络协议 互联网的本质就是一系列的网络协议,让不同计算机能够互 ...

  6. TCP/IP传输层协议实现 - TCP的超时与重传(lwip)

    (参考<TCP-IP详解卷 1:协议> 第21章 TCP的超时与重传) 1.往返时间测量(RTT) 1.1.分组交换和RTT测量示例 <TCP-IP详解卷 1:协议>中分组交换 ...

  7. TCP/IP传输层协议实现 - TCP接收窗口/发送窗口/通告窗口(lwip)

    1.tcp通告窗口/接收窗口/发送窗口 接收端有一个接收窗口大小,接收端只能接收这么多数据,接收窗口的数据需要被上层接收后才释放更大接收空间,才可以接收更多数据:接收窗口之前的数据已经被接收,再次接收 ...

  8. TCP/IP传输层协议实现 - TCP的坚持定时器(lwip)

    (参考<TCP-IP详解卷 1:协议>"第22章 TCP的坚持定时器") 1.糊涂窗口综合症 <TCP-IP详解卷 1:协议>"22.3 糊涂窗口 ...

  9. 划重点 传输层协议 tcp三次握手和四次挥手

    文章目录 传输层的协议 1.TCP/IP协议组的传输层协议 2. TCP报文段 3.TCP建立连接的过程 3.2 TCP常用端口号及其功能 4.UDP协议 4.1 UDP报文的首部格式 4.2 UDP ...

  10. 4-1:TCP协议之传输层的作用及传输层协议TCP和UDP

    文章目录 一:传输层的定义 二:通信处理 三:传输层协议 四:TCP协议的可靠和性能 一:传输层的定义 前面说过,IP首部有一个协议字段用于标识网络层(IP)的上一层采用哪一种传输层协议.根据这个字段 ...

最新文章

  1. c语言中external,static关键字用法
  2. 行人检测资源综述文献
  3. 洛谷——P2590 [ZJOI2008]树的统计(树链剖分模板练手)
  4. 太原理工软件学院c语言2020,太原理工软件工程C语言实验报告 数组.doc
  5. Python-读取文件:API介绍
  6. Taro+react开发(77):taro项目目录介绍
  7. SharpGL学习笔记(一) 平台构建与Opengl的hello World (转)
  8. ASP.NET-关于Container dataitem 与 eval方法介绍(转帖)
  9. scratch 控制、侦测、数据和数字逻辑模块  教案
  10. pascal行人voc_Pascal Voc数据集详细分析
  11. Activiti7使用
  12. review board 使用
  13. excel数据处理技巧笔记
  14. php实现ipv4转换ipv6
  15. 软件测试工具常用的都有哪些?
  16. 常见高清视频“扩展名”、视频标准
  17. MYSQL_DQL语言的学习(1)
  18. 让div占据父元素剩下的所有位置
  19. 模型prun quantization related paper
  20. PCB线路板的制作工艺流程分享!2021-08-21

热门文章

  1. 解决Charles Response 中文乱码
  2. Delphi中ListView和TreeView的Item中的内存泄露
  3. android api文档中文版_干货分享 | Android 存储空间的最佳实践 (下)
  4. matlab练习程序(图像错切)
  5. BZOJ2006:[NOI2010]超级钢琴——题解
  6. BZOJ1085:[SCOI2005]骑士精神——题解+IDA*粗略讲解
  7. apt-get install
  8. Xtrabackup--InnoDB备份工具介绍(1)
  9. PHP 中 json_encode中文处理、urlencode方法、post中文乱码
  10. XHTML跟HTML的区别