這種公司不去也罷!
大家好,我是小林。上周有位讀者在面試的時候,碰到這么個問題:
面試官跟他說 HTTPS 中的 TLS 握手過程可以同時進行三次握手,然后讀者之前看我的文章是說「先進行 TCP 三次握手,再進行 TLS 四次握手」,他跟面試官說了這個,面試官說他不對,他就感到很困惑。
我們先不管面試官說的那句「HTTPS 中的 TLS 握手過程可以同時進行三次握手」對不對。
但是面試官說「HTTPS 建立連接的過程,先進行 TCP 三次握手,再進行 TLS 四次握手」是錯的,這很明顯面試官的水平有問題,這種公司不去也罷!
如果是我面試遇到這樣的面試官,我直接當場給他抓 HTTPS 建立過程的網(wǎng)絡包,然后給他看,啪啪啪啪啪的打他臉。
比如,下面這個 TLSv1.2 的 基于 RSA 算法的四次握手過程:
難道不是先三次握手,再進行 TLS 四次握手嗎?面試官你臉疼嗎?
不過 TLS 握手過程的次數(shù)還得看版本。
TLSv1.2 握手過程基本都是需要四次,也就是需要經(jīng)過 2-RTT 才能完成握手,然后才能發(fā)送請求,而 TLSv1.3 只需要 1-RTT 就能完成 TLS 握手,如下圖。
一般情況下,不管 TLS 握手次數(shù)如何,都得先經(jīng)過 TCP 三次握手后才能進行,因為 HTTPS 都是基于 TCP 傳輸協(xié)議實現(xiàn)的,得先建立完可靠的 TCP 連接才能做 TLS 握手的事情。
那面試官說的這句「HTTPS 中的 TLS 握手過程可以同時進行三次握手」對不對呢?
這個場景是可能發(fā)生的,但是需要在特定的條件下才可能發(fā)生,如果沒有說任何前提條件,說這句話就是在耍流氓。
那到底什么條件下,這個場景才能發(fā)生呢?需要下面這兩個條件同時滿足才可以:
- 客戶端和服務端都開啟了 TCP Fast Open 功能,且 TLS 版本是 1.3;
- 客戶端和服務端已經(jīng)完成過一次通信。
那具體怎么做到的呢?我們先了解些 TCP Fast Open 功能和 TLSv1.3 的特性。
TCP Fast Open
我們先來了解下什么是 TCP Fast Open?
常規(guī)的情況下,如果要使用 TCP 傳輸協(xié)議進行通信,則客戶端和服務端通信之前,先要經(jīng)過 TCP 三次握手后,建立完可靠的 TCP 連接后,客戶端才能將數(shù)據(jù)發(fā)送給服務端。
其中,TCP 的第一次和第二次握手是不能夠攜帶數(shù)據(jù)的,而 TCP 的第三次握手是可以攜帶數(shù)據(jù)的,因為這時候客戶端的 TCP 連接狀態(tài)已經(jīng)是 ESTABLISHED,表明客戶端這一方已經(jīng)完成了 TCP 連接建立。
就算客戶端攜帶數(shù)據(jù)的第三次握手在網(wǎng)絡中丟失了,客戶端在一定時間內(nèi)沒有收到服務端對該數(shù)據(jù)的應答報文,就會觸發(fā)超時重傳機制,然后客戶端重傳該攜帶數(shù)據(jù)的第三次握手的報文,直到重傳次數(shù)達到系統(tǒng)的閾值,客戶端就會銷毀該 TCP 連接。
說完常規(guī)的 TCP 連接后,我們再來看看 TCP Fast Open。
TCP Fast Open 是為了繞過 TCP 三次握手發(fā)送數(shù)據(jù),在 Linux 3.7 內(nèi)核版本之后,提供了 TCP Fast Open 功能,這個功能可以減少 TCP 連接建立的時延。
要使用 TCP Fast Open 功能,客戶端和服務端都要同時支持才會生效。
不過,開啟了 TCP Fast Open 功能,想要繞過 TCP 三次握手發(fā)送數(shù)據(jù),得建立第二次以后的通信過程。
在客戶端首次建立連接時的過程,如下圖:
具體介紹:
- 客戶端發(fā)送 SYN 報文,該報文包含 Fast Open 選項,且該選項的 Cookie 為空,這表明客戶端請求 Fast Open Cookie;
- 支持 TCP Fast Open 的服務器生成 Cookie,并將其置于 SYN-ACK 報文中的 Fast Open 選項以發(fā)回客戶端;
- 客戶端收到 SYN-ACK 后,本地緩存 Fast Open 選項中的 Cookie。
所以,第一次客戶端和服務端通信的時候,還是需要正常的三次握手流程。隨后,客戶端就有了 Cookie 這個東西,它可以用來向服務器 TCP 證明先前與客戶端 IP 地址的三向握手已成功完成。
對于客戶端與服務端的后續(xù)通信,客戶端可以在第一次握手的時候攜帶應用數(shù)據(jù),從而達到繞過三次握手發(fā)送數(shù)據(jù)的效果,整個過程如下圖:
我詳細介紹下這個過程:
- 客戶端發(fā)送 SYN 報文,該報文可以攜帶「應用數(shù)據(jù)」以及此前記錄的 Cookie;
- 支持 TCP Fast Open 的服務器會對收到 Cookie 進行校驗:如果 Cookie 有效,服務器將在 SYN-ACK 報文中對 SYN 和「數(shù)據(jù)」進行確認,服務器隨后將「應用數(shù)據(jù)」遞送給對應的應用程序;如果 Cookie 無效,服務器將丟棄 SYN 報文中包含的「應用數(shù)據(jù)」,且其隨后發(fā)出的 SYN-ACK 報文將只確認 SYN 的對應序列號;
- 如果服務器接受了 SYN 報文中的「應用數(shù)據(jù)」,服務器可在握手完成之前發(fā)送「響應數(shù)據(jù)」,這就減少了握手帶來的 1 個 RTT 的時間消耗;
- 客戶端將發(fā)送 ACK 確認服務器發(fā)回的 SYN 以及「應用數(shù)據(jù)」,但如果客戶端在初始的 SYN 報文中發(fā)送的「應用數(shù)據(jù)」沒有被確認,則客戶端將重新發(fā)送「應用數(shù)據(jù)」;
- 此后的 TCP 連接的數(shù)據(jù)傳輸過程和非 TCP Fast Open 的正常情況一致。
所以,如果客戶端和服務端同時支持 TCP Fast Open 功能,那么在完成首次通信過程后,后續(xù)客戶端與服務端 的通信則可以繞過三次握手發(fā)送數(shù)據(jù),這就減少了握手帶來的 1 個 RTT 的時間消耗。
TLSv1.3
說完 TCP Fast Open,再來看看 TLSv1.3。
在最開始的時候,我也提到 TLSv1.3 握手過程只需 1-RTT 的時間,它到整個握手過程,如下圖:
TCP 連接的第三次握手是可以攜帶數(shù)據(jù)的,如果客戶端在第三次握手發(fā)送了 TLSv1.3 第一次握手數(shù)據(jù),是不是就表示「HTTPS 中的 TLS 握手過程可以同時進行三次握手」?。
不是的,因為服務端只有在收到客戶端的 TCP 的第三次握手后,才能和客戶端進行后續(xù) TLSv1.3 握手。TLSv1.3 還有個更厲害到地方在于會話恢復機制,在重連 TLvS1.3 只需要 0-RTT,用“pre_shared_key”和“early_data”擴展,在 TCP 連接后立即就建立安全連接發(fā)送加密消息,過程如下圖:
TCP Fast Open + TLSv1.3
在前面我們知道,客戶端和服務端同時支持 TCP Fast Open 功能的情況下,在第二次以后到通信過程中,客戶端可以繞過三次握手直接發(fā)送數(shù)據(jù),而且服務端也不需要等收到第三次握手后才發(fā)送數(shù)據(jù)。
如果 HTTPS 的 TLS 版本是 1.3,那么 TLS 過程只需要 1-RTT。
因此如果「TCP Fast Open + TLSv1.3」情況下,在第二次以后的通信過程中,TLS 和 TCP 的握手過程是可以同時進行的。
如果基于 TCP Fast Open 場景下的 TLSv1.3 0-RTT 會話恢復過程,不僅 TLS 和 TCP 的握手過程是可以同時進行的,而且 HTTP 請求也可以在這期間內(nèi)一同完成。
總結
最后做個總結。
「HTTPS 是先進行 TCP 三次握手,再進行 TLSv1.2 四次握手」,這句話一點問題都沒有,懷疑這句話是錯的人,才有問題。
「HTTPS 中的 TLS 握手過程可以同時進行三次握手」,這個場景是可能存在到,但是在沒有說任何前提條件,而說這句話就等于耍流氓。需要下面這兩個條件同時滿足才可以:
- 客戶端和服務端都開啟了 TCP Fast Open 功能,且 TLS 版本是 1.3;
- 客戶端和服務端已經(jīng)完成過一次通信;
怎么樣,那位“面試官”學廢了嗎?