文章目录
前言
介于TCP协议中三次握手经常会被问到,以及TCP三次握手存在脆弱性会导致我们企业的开放服务器可能会面临黑客的恶意攻击,所以笔者打算用本文简单介绍一下TCP协议中的三次握手到底是什么,以及介绍一下黑客如何利用三次握手的脆弱性来进行攻击。
术语
- TCP协议:IETF组织通过RFC 9293(最新)定义的传输层控制协议。是个Specification,和JVM Specification可以被许多不同厂商实现一样,TCP的实现(Implementation)也有很多。
- TCP通信组件:TCP Peer,实现了TCP协议的实际通信组件,通常是操作系统级别实现的。
- 开放服务器:企业大量服务器中,处于内网、外网交界地方的服务器,即需要承受外部网络请求的第一站。
- TCP Client:TCP客户端,是TCP通信组件的一种。通常指TCP连接的发起方。
- TCP Server:TCP服务器,也是TCP通信组件的一种。通常指接受TCP连接请求的服务提供方。
- 同步:同步(synhronize),用白话来讲就是多个实体合计一下它们所掌握的情报(数据)。计算机中通常指代两个组件把各自手头掌握的数据调整到一致的这么个过程。
TCP协议三次握手的由来
三次握手,这个词并不是国人发明,在RFC 9293中,IETF组织就提到了three-way handshake,参考rfc9293的截图:
至于三次握手时什么,截图里其实也说得非常清楚了,three-way handshake是用来建立tcp连接的一个处理(procedure),通常是由一个TCP通信组件发起,由另一个TCP通信组件响应。这里还提到了同时(simultaneously)发起初始化的情况,不过这里咱们不讨论。
我们仅讨论最普遍的一个情况:TCP Client发起初始化,TCP Server响应初始化。
在上述的情况下呢,我们的TCP协议约定了TCP Client与TCP Server双方(两个TCP通信组件)需要靠三次通信来做通信组件自身的初始化工作。
RFC 9293里面也为三次握手配了图:
网络协议里的握手阶段
在进程中按照某协议制定的规则负责进行通信的通信组件呢,通常都是位于不同机器的不同进程里,所以在正常传递数据之前,会有做元信息(meta-data)同步的需求。这个阶段通常被称为握手阶段。
举个例子就是:
- TCP协议:握手阶段同步了双方的初始Sequence Number元信息。(Sequence Number信息对TCP协议非常重要,这个我们后面讨论)
- TLS协议:握手阶段同步了双方的加密方式、加密参数等元信息。
如果读者对TLS协议不太了解且有兴趣了解的话,可以移步笔者以前写的这篇文章:《[网络] https是什么?https是怎么保障我们信息传输的安全的?》里面有讨论TLS协议的部分。
Sequence Number是什么?
在了解TCP三次握手之前,我们需要先了解TCP的重要概念之Sequence Number。
Sequence Number,中译:序列号。RFC中对其描述如下图:
简单来说呢,就是TCP协议中每一个字节的数据(every octet of data)都有其单独的序列号。数据的接收方会通过承认机制(Acknowledgment mechanism)去告知数据的发送方哪些数据已经被成功接收了。
也正是因为这种数据接收后告知对方数据是否送达的机制,使得如果一旦发生数据包丢失,发送方可以重发(retransmission)丢失数据包,使得TCP通信变得可靠。同一层的UDP协议没有这种送达回执和重发的机制,导致其使用UDP通信呢,是不可靠的。
TCP协议三次握手都发送了什么数据?
文章到这里,我们已经了解了TCP三次握手的由来和对于TCP通信组件来说非常重要的数据之Sequence Number。
我们也提到了TCP协议三次握手其实是同步初始Sequence Number这一元信息的一个过程。
对于使用TCP协议通信的两个通信组件(TCP Client和TCP Server)来说,无论是哪一方,都可以是数据的发送方和接收方,这意味着TCP Client有自己的一个初始Sequence Number,TCP Server也有自己的一个初始Sequence Number。双方在最初开始建立连接时,并不知道对方的初始Sequence Number,所以需要互相交换初始Sequence Number 并 互相承认。
那我们再来回看这个图:
简单解释如下:
No. | TCP客户端状态 | 消息(数据) | TCP服务器状态 | 描述 | ||
---|---|---|---|---|---|---|
1 | CLOSED | LISTTEN(监听) | ||||
2 | SYN-SENT | → | <SEQ=100><CTL=SYN> | → | SYN-RECEIVED | 第一次握手:客户端发起同步请求,初始序列号100 |
3 | ESTABLISHED | ← | <SEQ=300><ACK=101><CTL=SYN,ACK> | ← | SYN-RECEIVED | 第二次握手:服务端承认客户端同步请求,并发起同步请求,初始序列号为300 |
4 | ESTABLISHED | → | <SEQ=101><ACK=301><CTL=ACK> | → | EStABLISHED | 第三次握手:客户端承认服务端的同步请求。 |
5 | ESTABLISHED | → | <SEQ=101><ACK=301><CTL=ACK><DATA> | → | EStABLISHED | 以上三次握手后,双方的状态都变为ESTABLISHED ,即可正常发送数据了 |
可以看到其实三次握手发送的数据还是非常的简单,就是双方的一个初始序列号信息以及承认这个信息而已。如果你依然不理解<SEQ=100><CTL=SYN>这种消息的表达方式,可以结合下一章来理解。
TCP数据包长什么样?
TCP 数据包的格式呢,笔者贴在下面了。
那么我们结合这个图来看一下如<SEQ=300><ACK=101><CTL=SYN,ACK>这种信息代表着什么:
- SEQ:第二排的Sequence Number就是我们的序列号信息所存放的地方。<SEQ=300>意味着这里携带的数据是100。
- ACK:第三排的Acknowledgment Number就是我们数据接收方承认(ACK)序列号信息所存放的地方。<ACK=101>意味着这里携带的数据是101。
- CTL:CTL全称Control,通常是标志位的集合,在TCP中呢表现为第四排的第二个字节。<CTL=SYN,ACK>意味着这个字节是0b00010010,即ACK和SYN标志位为1。
SYN Flood DDOS攻击是什么?
我们了解了TCP三次握手建立连接的原理之后。就不得不提一个与之相关的DDOS攻击了:SYN Flood,SYN泛洪攻击。SYN Flood Attack也被称为半开连接攻击(Half-open attack)。
还记得我们的三次握手吗?
- 客户端发送SYN
- 服务端回复SYN、ACK
- 客户端回复ACK
一般情况下,正常的TCP Client发起连接请求开启三次握手处理后,都能非常快速地完成三次握手的处理过程。
那么如果在第三次握手时,恶意开发的TCP客户端故意不回复ACK,那么我们的TCP连接就将处于一个半开(Half-Open)的抽象状态。这时我们的服务端通常会等待至超时(TIMEOUT)然后废弃这个半开连接。这个超时时间通常被认为是分钟(minute)级别的,一旦大量肉鸡利用这种半开连接攻击,会导致服务器的资源快速耗尽,进而无法向正常客户端提供服务。
至于如何解决这种半开连接攻击,很抱歉笔者作为一个应用开发者目前还没有服务器运维相关的知识去应对这种攻击,这通常是infrastructure team或是security team需要去考虑和担心的事情,有兴趣的读者只能自行查阅了。
结语
协议的设计者并不是神,它们能提供某项特性的同时,也一定需要额外的元信息,这些额外的元信息通常需要在两个通信组件中做数据同步,这个同步的过程被称为握手(handshake)。理解了这一点,笔者相信咱们再去理解其他网络协议的握手处理时,就能把握住其最主要的目的,能够更好更快速地理解协议设计者为什么设计。
我是虎猫,希望本文对你有帮助。(=・ω・=)