TCP Fast Open
4.14 HTTPS 中 TLS 和 TCP 能同时握手吗?
比如,下面这个 TLSv1.2 的 基于 RSA 算法的四次握手过程:

难道不是先三次握手,再进行 TLS 四次握手吗?
不过 TLS 握手过程的次数还得看版本。
TLSv1.2 握手过程基本都是需要四次,也就是需要经过 2-RTT 才能完成握手,然后才能发送请求,
而 TLSv1.3 只需要 1-RTT 就能完成 TLS 握手,如下图。

一般情况下,不管 TLS 握手次数如何,都得先经过 TCP 三次握手后才能进行,因为 HTTPS 都是基
于 TCP 传输协议实现的,得先建立完可靠的 TCP 连接才能做 TLS 握手的事情。
那面试官说的这句「HTTPS 中的 TLS 握手过程可以同时进行三次握手」对不对呢?
这个场景是 可能发生的,但是需要在特定的条件下才可能发生,如果没有说任何 前提条件,说这
句话就是在耍流氓。
那到底什么 条件下,这个场景才能发生呢?需要下面这两个 条件同时满足才可以:
客⼾端和服务端都开启了 TCP Fast Open 功能,且 TLS 版本是 1.3 ;
客⼾端和服务端已经完成过一次通信。
那具体怎么做到的呢?我们先了解些 TCP Fast Open 功能和 TLSv1.3 的特性。
TCP Fast Open
我们先来了解下什么 是 TCP Fast Open ?
常规的情况下,如果要使用 TCP 传输协议进行通信,则客⼾端和服务端通信之前,先要经过 TCP
三次握手后,建立完可靠的 TCP 连接后,客⼾端才能将数据发送给服务端。
其中,TCP 的第一次和第二次握手是不能够携带数据的,而 TCP 的第三次握手是可以携带数据
的,因为这时候客⼾端的 TCP 连接状态已经是 ESTABLISHED ,表明客⼾端这一方已经完成了 TCP
连接建立。

就算客⼾端携带数据的第三次握手在网络中丢 失了,客⼾端在一定时间内没有收到服务端对该数
据的应答报文,就会触发超时重传机制,然后客⼾端重传该携带数据的第三次握手的报文,直到
重传次数达到系统的阈值,客⼾端就会销毁该 TCP 连接。
说完常规的 TCP 连接后,我们再来看看 TCP Fast Open 。
TCP Fast Open 是为了 绕过 TCP 三次握手发送数据,在 Linux 3.7 内核版本之后,提供了 TCP Fast Open 功能,这个功能可以减少 TCP 连接建立的时延。
要使用 TCP Fast Open 功能,客⼾端和服务端都要同时支持才会生效。
不过,开启了 TCP Fast Open 功能,想要绕过 TCP 三次握手发送数据,得建 立第二次以后的通信
过程。
在客⼾端首次建立连接时的过程,如下图:

具体介绍:
客⼾端发送 SYN 报文,该报文包含 Fast Open 选项,且该选项的 Cookie 为空,这表明客⼾端
请求 Fast Open Cookie ;
支持 TCP Fast Open 的服务器生成 Cookie ,并将其置于 SYN-ACK 报文中的 Fast Open 选项以
发回客⼾端;
客⼾端收到 SYN-ACK 后,本地缓存 Fast Open 选项中的 Cookie 。
所以,第一次客⼾端和服务端通信的时候,还是需要正常的三次握手流程。随后,客⼾端就有了
Cookie 这个东 西,它可以用来向服务器 TCP 证明先前与客⼾端 IP 地址 的三向握手已成功完成。
对于客⼾端与服务端的后续通信,客⼾端可以在第一次握手的时候携带应 用数据,从而达到绕过
三次握手发送数据的效果,整个过程如下图:

我详细介绍下这个过程:
客⼾端发送 SYN 报文,该报文可以携带「应用数据」以及此前记录的 Cookie ;
支持 TCP Fast Open 的服务器会对收到 Cookie 进行校验:如果 Cookie 有效,服务器将在 SYN-ACK 报文中对 SYN 和「数据」进行确认,服务器随后将「应用数据」递送 给对应的应用程序;
如果 Cookie 无效,服务器将丢弃 SYN 报文中包含的「应用数据」,且其随后发出的 SYN-ACK
报文将只确认 SYN 的对应序 列号;
如果服 务器接受了 SYN 报文中的「应用数据」,服务器可在握手完成之前发送「响应数据」,这
就减少了握手带来的 1 个 RTT 的时间消耗;
客⼾端将发送 ACK 确认服务器发回的 SYN 以及「应用数据」,但如果客⼾端在初始的 SYN 报文
中发送的「应用数据」没有被确认,则客⼾端将重新发送「应用数据」;
此后的 TCP 连接的数据传输过 程和非 TCP Fast Open 的正常情况一致。
所以,如果客⼾端和服务端同时支持 TCP Fast Open 功能,那么在完成首次通信过程后,后续客⼾
端与服务端 的通信则可以绕过三次握手发送数据,这就减少了握手带来的 1 个 RTT 的时间消耗。
TLSv1.3
说完 TCP Fast Open ,再来看看 TLSv1.3 。
在最开始的时候,我也提到 TLSv1.3 握手过程只需 1-RTT 的时间,它到整个握手过程,如下图:

TCP 连接的第三次握手是可以携带数据的,如果客⼾端在第三次握手发送了 TLSv1.3 第一次握手数
据,是不是就表示「HTTPS
中的 TLS
握手过程可以同时进行三次握手」?。
不是的,因为服务端只有在收到客⼾端的 TCP 的第三次握手后,才能和客⼾端进行后续 TLSv1.3
握手。
TLSv1.3 还有个更厉害到地方在于会话恢复机制,在重连 TLvS1.3 只需要 0-RTT ,
用“pre_shared_key” 和“early_data” 扩展,在 TCP 连接后立即就建立安全连接发送加密消息,过程如
下图:

TCP Fast Open + TLSv1.3
在前面我们知道,客⼾端和服务端同时支持 TCP Fast Open 功能的情况下,在第二次以后到通信过
程中,客⼾端可以绕过三次握手直接发送数据,而且服务端也不 需要等收到第三次握手后才发送
数据。
如果 HTTPS 的 TLS 版本是 1.3 ,那么 TLS 过程只需要 1-RTT 。
因此如果「TCP Fast Open + TLSv1.3 」情况下,在第二次以后的通信过程中,TLS 和 TCP 的握手
过程是可以同时进行的。
如果基于 TCP Fast Open 场景下的 TLSv1.3 0-RTT 会话恢复过程,不仅 TLS 和 TCP 的握手过程是
可以同时进行的,而且 HTTP 请求也可以在这期间内一同完成。
总结
最后做个总结。
「HTTPS 是先进行 TCP 三次握手,再进行 TLSv1.2 四次握手」,这句话一点问题都没有,怀疑这句
话是错的人,才有问题。
「HTTPS 中的 TLS 握手过程可以同时进行三次握手」,这个场景是 可能存在到,但是在没有说任何
前提条件,而说这句话就等于耍流氓。需要下面这两个 条件同时满足才可以:
客⼾端和服务端都开启了 TCP Fast Open 功能,且 TLS 版本是 1.3 ;
4.15 TCP Keepalive 和 HTTP Keep-Alive 是一个东 西吗? →
Powered by GitHub & Vssue
客⼾端和服务端已经完成过一次通信;
怎么样,学废了吗?
