Wireshark 抓包理解 HTTPS 請(qǐng)求流程

目錄

  1. 準(zhǔn)備
  2. 分析
    2.1. 三次握手
    2.2. 創(chuàng)建 HTTP 代理(非必要)
    2.3. TLS/SSL 握手
    2.4. 數(shù)據(jù)傳輸
    2.5. 四次揮手
  3. 擴(kuò)展
    3.1. Session ID 和 Session Ticket
    3.2. SNI(Server Name Indication)
    3.3. ALPN(Application Layer Protocol Negotiation)
  4. 資料

1. 準(zhǔn)備

我的操作是這樣的,讓手機(jī)和電腦在同一個(gè)局域網(wǎng)內(nèi)(比如連接同一個(gè) wifi),接著在手機(jī)的wifi上設(shè)置代理,電腦使用 Charles 做代理,IP 為電腦在局域網(wǎng) IP,我這邊的環(huán)境,手機(jī) IP 為 172.17.32.117,電腦 IP 為 172.17.32.19。再設(shè)置代理端口為 8888。設(shè)置代理后,接下來(lái)手機(jī)的請(qǐng)求都會(huì)通過(guò)電腦的網(wǎng)卡代理請(qǐng)求發(fā)送出去。

其實(shí)可以不用這么繞。我之所以多設(shè)了一個(gè)代理,是因?yàn)樽约弘娔X創(chuàng)建的 wifi 熱點(diǎn),手機(jī)接收不到。為了讓手機(jī)的包能經(jīng)過(guò)電腦網(wǎng)絡(luò)嗅探到才這么處理的。

最便捷的方式,就是電腦放個(gè) wifi 熱點(diǎn)給手機(jī)連接完事。

創(chuàng)建后代理連接后,然后使用 Wireshark 嗅探網(wǎng)卡,比如我這里使用的是 etho0 網(wǎng)卡去訪問(wèn)網(wǎng)絡(luò)的。這時(shí)候玩玩手機(jī),打開幾個(gè)請(qǐng)求,Wireshark 上面就會(huì)出現(xiàn)捕捉的大量的包,各種各樣的協(xié)議都有,有 ARP 尋人啟事(尋找 IP 對(duì)應(yīng)的物理地址),有 TCP 連接包,有 HTTP 請(qǐng)求包。

請(qǐng)求數(shù)據(jù)

這里我設(shè)置了一下過(guò)濾規(guī)則,把對(duì)網(wǎng)易的一個(gè) https://nex.163.com 的一個(gè)的請(qǐng)求過(guò)濾出來(lái)如下:

HTTPS 連接數(shù)據(jù)

整個(gè)完整的 HTTPS 請(qǐng)求的過(guò)程如下:

  • TCP 三次握手。
  • 因?yàn)槲沂褂秒娔X作為代理,所以還有一個(gè) CONNECT 請(qǐng)求用來(lái)建立 HTTP 代理。
  • 使用 TLSv1.2 進(jìn)行 SSL 握手。
  • 使用握手協(xié)商好的密鑰對(duì) HTTP 進(jìn)行加密傳輸。
  • TCP 四次揮手。

接下來(lái)把手機(jī)稱為 A(172.17.32.211),電腦稱為 B(172.17.32.19),對(duì)完整的過(guò)程進(jìn)行簡(jiǎn)要分析。

2. 分析

2.1. 三次握手

2.1.1. TCP 協(xié)議內(nèi)容

作為整個(gè)過(guò)程的第一個(gè) TCP 包,這里對(duì)它做一個(gè)詳細(xì)的剖析,理解一下 TCP 報(bào)文的格式和內(nèi)容。TCP 是傳輸層協(xié)議,負(fù)責(zé)可靠的數(shù)據(jù)通信,它在整個(gè)體系結(jié)構(gòu)的位置如下:

計(jì)算機(jī)網(wǎng)絡(luò)體系結(jié)構(gòu)

作為傳輸層協(xié)議,主要為上層協(xié)議提供三個(gè)功能:

  • 可靠傳輸,為每個(gè)字節(jié)安排好序號(hào),排好序,并且有重傳機(jī)制保證信息不丟失。
  • 流量控制,有滑動(dòng)窗口,避免發(fā)送端和接收端速率不一致導(dǎo)致發(fā)包過(guò)快來(lái)不及接收。
  • 擁塞避免,在網(wǎng)絡(luò)環(huán)境差的時(shí)候,控制好傳包的時(shí)間間隔,避開高峰期,不給原本已經(jīng)很擁堵的網(wǎng)絡(luò)添堵。

TCP 協(xié)議為 HTTP 和 SSL 協(xié)議提供了基礎(chǔ)的通信功能。所以 SSL 協(xié)議是基于 TCP 的。

三次握手的內(nèi)容有:

No. Time Source Destionation Protocol Length Info
379 4.623811 172.17.32.211 172.17.32.19 TCP 74 35973 → 8888 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15986187 TSecr=0 WS=256
380 4.623860 172.17.32.19 172.17.32.211 TCP 74 8888 → 35973 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1 TSval=59355465 TSecr=15986187
393 4.781431 172.17.32.211 172.17.32.19 TCP 66 35973 → 8888 [ACK] Seq=1 Ack=1 Win=87808 Len=0 TSval=15986193 TSecr=59355465

對(duì)每個(gè)包進(jìn)行詳細(xì)的分析:

2.1.2. Round 1

A 發(fā)出一個(gè)帶 SYN 同步位的包,通知服務(wù)端要建立連接。

第一次握手,發(fā)出的 TCP 包的數(shù)據(jù)和 Wireshark 解析的結(jié)果如下:

第一次握手

灰色部分就是 TCP 報(bào)文的數(shù)據(jù)內(nèi)容,第一個(gè)兩個(gè)字節(jié) 0x8c85 = 35973 表示源端口。

TCP 報(bào)文的格式如下,對(duì)應(yīng)的如上圖的灰色部分。非灰色部分分別為 IP 首部和數(shù)據(jù)幀首部。

 0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    源端口                      |                     目的端口                   |
+-----------------------------------------------+-----------------------------------------------+
|                                             序列號(hào)                                             |
+-----------------------------------------------------------------------------------------------+
|                                             確認(rèn)號(hào)                                             |
+-----------+-----------------+-----------------+-----------------------------------------------+
|  首部長(zhǎng)度  |     保留位       | U| A| P| R| S| F|                      窗口                      |
+-----------+-----------------+-----------------+-----------------------------------------------+
|                    校驗(yàn)和                      |                     緊急指針                   |
+-----------------------------------------------+-----------------------+-----------------------+
|                    選項(xiàng)                                                |        填充            |
+=======================================================================+=======================+
|                                             數(shù)據(jù)                                               |

參考謝希仁版本的 《計(jì)算機(jī)網(wǎng)絡(luò)》一書,對(duì)照著整個(gè)報(bào)文格式表,把整個(gè) TCP 報(bào)文的二進(jìn)制信息和相關(guān)意義做些說(shuō)明:

  • 源端口,2 字節(jié),0x8c85 = 35973。

  • 目的端口,2字節(jié),0x22b8 = 8888。

  • 序號(hào),4 字節(jié),0xc7a3ce5c。TCP 連接傳送的每一個(gè)字節(jié)都有編號(hào),而這里表示的是要發(fā)送的數(shù)據(jù)(data)的第一個(gè)字節(jié)的序號(hào)。后面按照這個(gè)序號(hào)遞增。這里發(fā)送的是 TCP 連接的第一個(gè)包,這里的序號(hào)是隨機(jī)產(chǎn)生的。

  • 確認(rèn)號(hào),4 字節(jié),0x00000000。期望收到的下一個(gè)報(bào)文段數(shù)據(jù)部分第一個(gè)字節(jié)的序號(hào)。如果發(fā)出了 N 確認(rèn)號(hào),就表示 N-1 之前的數(shù)據(jù)都收到了。

  • 首部長(zhǎng)度(偏移),4 位,0xa = 10。這里每一位表示4字節(jié),所以 10*4 = 40 字節(jié)。TCP 首部的長(zhǎng)度,因?yàn)?4 位最大的數(shù)為 15,所以整個(gè)首部最大 60 字節(jié)。首部后面就是數(shù)據(jù)字段。

  • 保留位,6 位,0x000。這里還沒(méi)有用到為 0,這里的設(shè)計(jì)作為一個(gè)擴(kuò)展以便未來(lái)會(huì)用上。

  • 控制位,6 位,0x002 = 二進(jìn)制 000010。每一位都有意義,這里對(duì)應(yīng) 6 種類型:

    • URG,Urgent,表示緊急數(shù)據(jù)要提交,有了這個(gè)標(biāo)記為整個(gè)報(bào)文就有了插隊(duì)的特權(quán),和緊急指針一起用。
    • ACK,Acknowledge,1 表示這是一個(gè)確認(rèn)報(bào)文,用來(lái)確認(rèn)收到了包,確認(rèn)報(bào)文是不帶數(shù)據(jù)的。
    • PSH,Push,1 表示這是一個(gè)推送報(bào)文,通知對(duì)方盡快響應(yīng)。因?yàn)榉?wù)端可能因?yàn)榫彺鎲?wèn)題要等了一會(huì)兒才發(fā)包。這里就是催促一下對(duì)方趕緊發(fā)包。
    • RST,Reset,1 表示拒絕了這個(gè)包,網(wǎng)絡(luò)發(fā)生錯(cuò)誤的時(shí)候這種包會(huì)非常多。比如重復(fù)的包就會(huì)被 reset 掉。
    • SYN,Synchronization,1 表示建立連接用來(lái)同步序號(hào)。用來(lái)握手階段,通知對(duì)方包的初始序號(hào)。
    • FIN,F(xiàn)inish,1 表示發(fā)送方 B 完成數(shù)據(jù)發(fā)送,通知接收方 A 該結(jié)束了。

    我們這里作為整個(gè)請(qǐng)求過(guò)程中的第一個(gè) TCP 報(bào)文,僅僅設(shè)置一個(gè)控制位 SYN,一方面通知響應(yīng)者 B 要建立連接了,另一方面同步一下序號(hào)。

  • 窗口,2 字節(jié),0xffff = 65535。發(fā)送本報(bào)文的接收窗口大小,比如 A 發(fā)送了這個(gè)報(bào)文,表示能接收的數(shù)據(jù)量為從確認(rèn)號(hào)算起來(lái)加上窗口大小,B 發(fā)送的報(bào)文字節(jié)數(shù)不能超過(guò)這個(gè)限制。這個(gè)值受 A 的緩存影響,是動(dòng)態(tài)變化的。前面給出確認(rèn)號(hào)為 0, 然后窗口大小 65535,表示還有 65535 的緩存空間可以接受序號(hào) 0 ~ 65535 的字節(jié)。

  • 檢驗(yàn)和,2 字節(jié),0x068f。接收方受到報(bào)文要計(jì)算一下數(shù)據(jù)包的檢驗(yàn)和是否和該值匹配,確保數(shù)據(jù)包的完整。這里只保證了數(shù)據(jù)完整性,并沒(méi)有確認(rèn)服務(wù)端身份,也沒(méi)有用摘要算法。目的在于能快速檢驗(yàn),而且采用檢驗(yàn)和的方式還可以使用硬件加速。

  • 緊急指針,2 字節(jié),0x0000f。和控制位 URG 配合使用,意義在于,有緊急數(shù)據(jù)要處理,這里的值表示緊急數(shù)據(jù)在報(bào)文中的位置。

到這里的話,TCP 數(shù)據(jù)報(bào)首部固定部分結(jié)束,固定部分一共有 20 字節(jié)。也就是 TCP 首部,至少要有 20 字節(jié)。

固定首部后,就是可長(zhǎng)度可以變化的選項(xiàng)了:

  • 選項(xiàng),可達(dá) 40 字節(jié)

    • 最大報(bào)文長(zhǎng)度,0x020405b4。0x2 表示這是個(gè) MSS 選項(xiàng),0x04 表示該選項(xiàng)一共有 4 字節(jié),這里的 0x05b4 = 1460 為該選項(xiàng)的值。這個(gè)表示 TCP 數(shù)據(jù)部分的最大字節(jié)數(shù)。

    • 時(shí)間戳,0x080a00f3ee0b00000000。0x8 表示這是個(gè)時(shí)間戳選項(xiàng),0x0a 表示該選項(xiàng)一共有 10 字節(jié),0x00f3ee = 15986187 就是發(fā)送者的發(fā)送時(shí)間,0x00000000 = 0 表示接收端的時(shí)間。

整個(gè)所以 TCP 數(shù)據(jù)包的大小可以這樣表示:

+------------------------+--------------------------------------------------------------+
|  TCP 首部,20 ~ 60 字節(jié) |           數(shù)據(jù)部分,受 MSS 大小限制                           |     
+------------------------+--------------------------------------------------------------+

我們 Wireshark 后面的一長(zhǎng)串的信息就指出了該 TCP 報(bào)文的一些主要信息:

35973 → 8888 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15986187 TSecr=0 WS=256
  • 源端口和目的端口,35973->8888。
  • 序號(hào),Seq=0,這是一個(gè)相對(duì)值而非絕對(duì)值,相對(duì)第一個(gè)包的序列號(hào)。因?yàn)槭钦麄€(gè) TCP 流的第一包,所以 Wireshark 認(rèn)定該包的序列號(hào)為 0。
  • 窗口大小,win=65535,也就是發(fā)送端的當(dāng)前窗口最多容納 65535 個(gè)字節(jié)。
  • 數(shù)據(jù)部分大小,Len=0,不帶數(shù)據(jù)。
  • 最大報(bào)文大小選擇,MSS=1460,數(shù)據(jù)部分最多有 1460 個(gè)字節(jié)。
  • 選擇確認(rèn)選項(xiàng),SACK_PERM=1。
  • 發(fā)送時(shí)間戳,TSval=15986187,發(fā)出這個(gè)數(shù)據(jù)包的時(shí)候的時(shí)間戳。
  • 應(yīng)答時(shí)間戳,TSecr=0,當(dāng)前要發(fā)送的包應(yīng)答的那個(gè)包的發(fā)送時(shí)間戳,因?yàn)槭堑谝粋€(gè)包,應(yīng)答的時(shí)間戳為 0。
  • 窗口擴(kuò)大,WS=256。

從上面的分析可以看出,這個(gè) SYN 包并沒(méi)有攜帶數(shù)據(jù),但是按協(xié)議這里要消耗一個(gè)序號(hào)。

在發(fā)出 SYN 包后,A 端進(jìn)入 SYN-SENT 狀態(tài)。

2.1.3. Round 2

B 收到 SYN 包,發(fā)出 SYN + ACK 確認(rèn)包

這個(gè)包,既是確認(rèn)收到了第一次握手的包,也是一個(gè)由 B 端發(fā)出的同步包,表示自己準(zhǔn)備好了,可以開始傳數(shù)據(jù)了。

因?yàn)?Wireshark 已經(jīng)幫我們分析好包的內(nèi)容了,上面列舉的包二進(jìn)制數(shù)據(jù)和 TCP 報(bào)文結(jié)構(gòu)只是為了學(xué)習(xí),實(shí)際應(yīng)用可以直接看 Wireshark 的解析內(nèi)容。包的內(nèi)容如下:
第二次握手

TCP 報(bào)文包相對(duì)于第一次握手的包可以窺見(jiàn)一些變化:

  • 源端口和目的端口:8888 -> 35973。

  • 窗口大小:8192,可以看成接收端的窗口只有 8192,和發(fā)送端差距還是挺大的。

  • 控制位:既有 SYN 又有 ACK。因?yàn)檫@既是一個(gè)接收端 B 的自己同步包,里面有一個(gè)接收端的初始序號(hào),Wireshark 轉(zhuǎn)化為相對(duì)序號(hào) 0;同時(shí)這也是對(duì)第一次握手的包的確認(rèn)。因此這個(gè)包也不帶數(shù)據(jù)。

  • 發(fā)送時(shí)間戳:59355465

  • 應(yīng)答時(shí)間戳:15986187

可以看到,這個(gè)包的應(yīng)答時(shí)間戳剛好是第一次握手的發(fā)送時(shí)間戳。從這里也可以理解到,這個(gè)包就是在響應(yīng)第一次握手的包

所以,接收方 A 可以利用這個(gè)值來(lái)計(jì)算這一次 RTT,收到第二次握手的包后,計(jì)算當(dāng)前時(shí)間戳減去該包的應(yīng)答時(shí)間戳就是一個(gè) RTT 的延時(shí)了。

這雖然是 ACK 包,但也是 SYN 包,所以也要消耗一個(gè)序號(hào)。

在發(fā)出這個(gè)包后,B 端進(jìn)入 SYN-REVD 狀態(tài)。

2.1.4. Round 3

A 收到后,再發(fā)出一個(gè) ACK 確認(rèn)包

發(fā)出的包如下:

No. Time Source Destionation Protocol Length Info
393 4.781431 172.17.32.211 172.17.32.19 TCP 66 35973 → 8888 [ACK] Seq=1 Ack=1 Win=87808 Len=0 TSval=15986193 TSecr=59355465

這里我們產(chǎn)生一個(gè)疑問(wèn),這里發(fā)送端 A 發(fā)連接請(qǐng)求信息、接收端 B 發(fā)確認(rèn)信息,又互相同步了序號(hào),是不是已經(jīng)可以傳輸數(shù)據(jù)了?但實(shí)際上 A 還要再發(fā)一個(gè) ACK 確認(rèn)報(bào)文,如圖所示,確認(rèn)收到了 B 第二次握手發(fā)出的包,這個(gè)時(shí)候,在這個(gè) ACK 包后 A 和 B 才正式進(jìn)入 ESTABLISHED 狀態(tài)。這就是第三次握手。

這是為什么呢?

假設(shè)我們用兩次握手,然后在第一次握手期間,A 發(fā)了第一次握手包后出現(xiàn)了這樣的場(chǎng)景:一直沒(méi)有得到響應(yīng)而進(jìn)行超時(shí)重傳,又發(fā)了一次包,然后我們稱上一次包為失效包。

然后我們可以看到:

  • 新包到達(dá)接收端 B,然后因?yàn)閮纱挝帐?B 覺(jué)得連接建立,于是等著發(fā)送端 A 發(fā)數(shù)據(jù),A 也發(fā)了數(shù)據(jù)。
  • 失效的包經(jīng)過(guò)艱苦跋涉,也到達(dá)了接收端 B,B 并不清楚這是失效包,又開始等待發(fā)送端 A 發(fā)數(shù)據(jù)。然而此時(shí) A 不發(fā)數(shù)據(jù),所以 B 的資源就浪費(fèi)掉了。

所以,只有接收端 B 在發(fā)送端 A 發(fā)出了第三次握手包后,才認(rèn)為連接已經(jīng)建立,開始等待發(fā)送端 A 發(fā)送的數(shù)據(jù),才不會(huì)因?yàn)槭У倪B接請(qǐng)求報(bào)文導(dǎo)致接收端異常。

2.1.5. 小結(jié)

TCP 三次握手的時(shí)序圖如下:

三次握手時(shí)序圖

三次握手,有幾個(gè)重要的任務(wù),一個(gè)是同步序號(hào),接收端和發(fā)送端都發(fā)出同步包來(lái)通知對(duì)方初始序號(hào),這樣子后面接收的包就可以根據(jù)序號(hào)來(lái)保證可靠傳輸;另一個(gè)是讓發(fā)送端和接收都做好準(zhǔn)備。然后就開始傳數(shù)據(jù)了。

整個(gè)過(guò)程都發(fā)生在 HTTP 報(bào)文發(fā)出之前。HTTP 協(xié)議就是依靠著 TCP 協(xié)議來(lái)做傳輸?shù)墓芾?。TCP 可以認(rèn)為是它的管家,管理著傳輸?shù)拇蟠笮⌒〉氖聞?wù),比如要不要保證包順序一致?什么時(shí)候發(fā)包?要不要收包?TCP 是很嚴(yán)格的。

三次握手在 Java API 層面,對(duì)應(yīng)的就是 Socket 的連接的創(chuàng)建(最終調(diào)用的是 native 層的 socket 創(chuàng)建):

socket.connect(address, connectTimeout);

這里的 connectTimeout 對(duì)應(yīng)的是三次握手的總時(shí)長(zhǎng),如果超時(shí)了就會(huì)被認(rèn)為連接失敗。

比如一個(gè)場(chǎng)景,客戶端發(fā)出一個(gè) SYN 報(bào)文后,遲遲沒(méi)有收到服務(wù)端的 SYN + ACK。這時(shí)候客戶端觸發(fā)重傳機(jī)制,每次重傳的間隔時(shí)間加倍,同樣沒(méi)有收到包。然后如果這段時(shí)間超出了連接超時(shí)時(shí)間的設(shè)置,那么建立連接超時(shí)就發(fā)生了。

所以,如果三次握手要花的時(shí)間,總是大于這里的 connectTimeout 時(shí)間,這個(gè) Socket 就無(wú)法建立連接。

我們這一次請(qǐng)求的三次握手時(shí)間在 180ms 左右。

像在 OkHttp 中,如果是三次握手階段的連接超時(shí),是會(huì)有重試機(jī)制的。也就是重新建聯(lián),重新發(fā)出 SYN 報(bào)文發(fā)起 TCP 連接。重新建聯(lián)的時(shí)候會(huì)更換連接的路由,如果已經(jīng)沒(méi)有可選擇路由的話,那么這個(gè)就真的失敗了。

在 OkHttp 3.9.0 的默認(rèn)配置中,連接超時(shí)的時(shí)間為 10000ms = 10s。在 OkHttpClient.Builder 中。

connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;

實(shí)際應(yīng)用的時(shí)候,根據(jù)業(yè)務(wù)場(chǎng)景來(lái)調(diào)整。

2.2. 創(chuàng)建 HTTP 代理(非必要)

這次請(qǐng)求,為了讓 Wireshark 抓到手機(jī)的包,我使用了電腦作為代理。

其實(shí)就是客戶端 A 使用 HTTP 協(xié)議和代理服務(wù)器 B 建立連接。和普通的 HTTP 請(qǐng)求一樣,需要攜帶 IP + 端口號(hào),如果有身份驗(yàn)證的時(shí)候還會(huì)帶上授權(quán)信息,代理服務(wù)器 B 會(huì)使用授權(quán)信息進(jìn)行驗(yàn)證。然后代理服務(wù)器會(huì)去連接遠(yuǎn)程主機(jī),連接成功后返回 200。

Wireshark 抓到的包有這樣兩條信息,就是在創(chuàng)建代理:

No. Time Source Destionation Protocol Length Info
396 4.798832 172.17.32.211 172.17.32.19 HTTP 284 CONNECT nex.163.com:443 HTTP/1.1
401 4.816127 172.17.32.19 172.17.32.211 HTTP 105 HTTP/1.0 200 Connection established

請(qǐng)求報(bào)文:

CONNECT nex.163.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (Linux; Android 6.0.1; MI 5 Build/MXB48T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/51.0.2704.81 Mobile Safari/537.36
Host: nex.163.com

響應(yīng)報(bào)文:

HTTP/1.0 200 Connection established

HTTP CONNECT 是在 HTTP1.1 新增的命令,用于支撐 https 加密。

因?yàn)槲也捎么淼姆绞阶グ庞羞@一個(gè)步驟。如果是直接抓 PC 機(jī)上瀏覽器發(fā)出的 HTTPS 包,不會(huì)有這個(gè)過(guò)程。

然后我們思考一下,為什么代理服務(wù)器需要這些信息,要連接的主機(jī)名和端口號(hào)?

這是因?yàn)楹竺孢M(jìn)行 SSL 加密 HTTP協(xié)議,因?yàn)榇矸?wù)器拿不到加密密鑰,是無(wú)法獲取到 HTTP 首部的,進(jìn)而無(wú)法這個(gè)請(qǐng)求是要發(fā)到哪個(gè)主機(jī)的。所以,這里先使用 CONNECT 方法,把主機(jī)名和對(duì)應(yīng)的端口號(hào)通知代理服務(wù)器。

這個(gè)也被稱為 HTTPS SSL 隧道協(xié)議。建立這個(gè) SSL 隧道后,這個(gè)特殊代理就會(huì)對(duì)數(shù)據(jù)進(jìn)行盲轉(zhuǎn)發(fā)。

2.3. TLS/SSL 握手

2.3.1. TLS/SSL 協(xié)議內(nèi)容

SSL 整個(gè)協(xié)議實(shí)際上分兩層,SSL 記錄協(xié)議和其他子協(xié)議(SSL握手協(xié)議,SSL改變密碼協(xié)議,SSL警告協(xié)議):

SSL 協(xié)議

這兩層協(xié)議的關(guān)系,其實(shí)就是數(shù)據(jù)封裝的關(guān)系,SSL 握手封裝協(xié)議封裝其他上層協(xié)議。

封裝握手協(xié)議:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 153
        Handshake Protocol: Client Hello

封裝應(yīng)用數(shù)據(jù)協(xié)議,比如 HTTP:

Secure Sockets Layer
    TLSv1.2 Record Layer: Application Data Protocol: http
        Content Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 1072
        Encrypted Application Data: 6d9b3c9089271630c33506fe28cd6a61fed1f4bd2808f537...

封裝交換密碼協(xié)議:

Secure Sockets Layer
    TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
        Content Type: Change Cipher Spec (20)
        Version: TLS 1.2 (0x0303)
        Length: 1
        Change Cipher Spec Message

封裝警報(bào)協(xié)議:

Secure Sockets Layer
    TLSv1.2 Record Layer: Encrypted Alert
        Content Type: Alert (21)
        Version: TLS 1.2 (0x0303)
        Length: 48
        Alert Message: Encrypted Alert

所以 SSL 記錄協(xié)議其實(shí)就是一個(gè)其他協(xié)議的載體,只是提供了一個(gè)封裝的功能。它的格式為:

| 內(nèi)容類型 | 主要版本 | 次要版本 | 長(zhǎng)度 |
|          明文/加密/壓縮 數(shù)據(jù)包       |
|          MAC(0, 16, 20)            |

MAC 就是消息驗(yàn)證碼,用來(lái)驗(yàn)證數(shù)據(jù)的完整性,保證中途沒(méi)有篡改。這個(gè)消息驗(yàn)證碼比數(shù)字簽名弱一些,使用的是對(duì)稱密鑰加密摘要。數(shù)字簽名使用的是非對(duì)稱密鑰加密,有區(qū)分公鑰私鑰。

記錄協(xié)議的主要目的有這幾個(gè),為其他 SSL 子協(xié)議提供了以下服務(wù):

  • 分組、組合。如果有幾個(gè)協(xié)議的內(nèi)容,是可以不用等客戶端確認(rèn)后再發(fā)送的,這里會(huì)進(jìn)行組合合并,然后在同一個(gè) TCP 包中發(fā)送。接收方接收到組合的 SSL 記錄協(xié)議報(bào)文,也會(huì)根據(jù)協(xié)議來(lái)進(jìn)行分組。
  • 壓縮、解壓縮??蛇x項(xiàng),如果需要壓縮的話。

  • 消息認(rèn)證(MAC)。注意,這里不提供數(shù)字簽名。消息認(rèn)證用的是用對(duì)稱密鑰,解密算法效率比公鑰算法快,安全性弱一些。如果已經(jīng)明確了,加密用的對(duì)稱密鑰只有合法的客戶端和服務(wù)端獲得,那么這個(gè)的安全效果和數(shù)字簽名一樣。

  • 加密傳輸 。比如已經(jīng)協(xié)商好加密密鑰和算法了,直接對(duì)應(yīng)用層協(xié)議加密傳輸:

    Encrypted Application Data: 6d9b3c9089271630c33506fe28cd6a61fed1f4bd2808f537...
    

TCP 三次握手結(jié)束并且和代理服務(wù)器成功連接后,建聯(lián)成功,客戶端 A 就開始發(fā)起 SSL 連接,首先會(huì)進(jìn)入 SSL 握手階段。

SSL 握手階段的主要目的有這么幾個(gè):

  • 協(xié)商加密算法。為了能夠提供效率,使用對(duì)稱密鑰。對(duì)稱加密使用的是位運(yùn)算,速度快,甚至可以硬件加速。非對(duì)稱加密比如 RSA,使用了大數(shù)乘法等,整體會(huì)比較慢。對(duì)稱加密只要密鑰沒(méi)有泄漏,那也是非常安全的。這也是后面 SSL 握手協(xié)議要確保的。
  • 協(xié)商加密密鑰 。用來(lái)對(duì)后面的 HTTP 協(xié)議等應(yīng)用協(xié)議內(nèi)容進(jìn)行加密。這個(gè)密鑰又稱為主密鑰,為加密算法的密鑰。
  • 驗(yàn)證身份 。通常情況下,只要驗(yàn)證服務(wù)端身份。特殊情況下,比如一些安全級(jí)別高的應(yīng)用場(chǎng)景,還要驗(yàn)證客戶端身份。服務(wù)端會(huì)返回證書鏈,有根 CA 證書在里頭。通過(guò)證書的鏈?zhǔn)綋?dān)保,可以確認(rèn)服務(wù)端是否是可信任的。同時(shí),在握手期間,公鑰傳輸成功后,還會(huì)對(duì)某些信息進(jìn)行數(shù)字簽名,確保數(shù)據(jù)沒(méi)有被篡改且身份無(wú)誤。

SSL 握手的流程并不是一成不變的,根據(jù)實(shí)際的應(yīng)用場(chǎng)景來(lái)。主要有三種:

  • 只驗(yàn)證服務(wù)端。這個(gè)用三個(gè)階段就完成握手,我們這次的請(qǐng)求也是這樣。一般的網(wǎng)絡(luò)請(qǐng)求也僅僅到這個(gè)程度。
  • 驗(yàn)證服務(wù)端和客戶端。在安全性要求較高的場(chǎng)景,服務(wù)端也要驗(yàn)證客戶端的身份。方式也是發(fā)證書證明自己。
  • 恢復(fù)原有會(huì)話 。這個(gè)屬于HTTPS 優(yōu)化的范疇。使用 Session Ticket 或者 Session ID 機(jī)制恢復(fù)之前已經(jīng)完成握手的會(huì)話。這個(gè)是可以允許在不同的 TCP 上進(jìn)行的。因?yàn)槲帐值募用軘?shù)據(jù)已經(jīng)保存,直接恢復(fù)就可以開始傳遞了。Session Ticket 由客戶端保存加密信息,Session ID 的方式由服務(wù)端保存加密信息。不過(guò) Session Ticket 在 Android 客戶端還沒(méi)有得到廣泛的支持,和具體機(jī)型和內(nèi)置的 OpenSSL 的版本有關(guān)。

SSL 握手的完整的交互過(guò)程如下,這里是驗(yàn)證服務(wù)端又驗(yàn)證了客戶端的情況:

SSL 握手

我們的請(qǐng)求只驗(yàn)證服務(wù)端,所以 7,8,9 是不存在的。

現(xiàn)在具體分析每一個(gè)階段的內(nèi)容。

2.3.2. 階段一

Client Hello

作為 SSL 握手的第一個(gè)握手包,我們?cè)敿?xì)分析和理解一下包的內(nèi)容。

下面是 Wireshark 解析好的這個(gè) SSL 協(xié)議的數(shù)據(jù)包:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 153
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 149
            Version: TLS 1.2 (0x0303)
            Random
                GMT Unix Time: Dec  1, 2050 02:37:13.000000000 ?й???????
                Random Bytes: 4e12e967b6169c4d67caf0575079f34b277d12318385f5a9...
            Session ID Length: 0
            Cipher Suites Length: 40
            Cipher Suites (20 suites)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 68
            Extension: server_name
            Extension: Extended Master Secret
            Extension: signature_algorithms
            Extension: ec_point_formats
            Extension: elliptic_curves

這個(gè)包如何解讀,按照之前對(duì) SSL 協(xié)議的分析,其實(shí)分成兩個(gè)部分:

  • SSL 握手協(xié)議。
  • SSL 記錄協(xié)議。

因?yàn)槭俏帐诌^(guò)程,密鑰還沒(méi)協(xié)商,這里還是使用明文傳輸,記錄協(xié)議的數(shù)據(jù)載體就是明文的 SSL 握手協(xié)議。

SSL 握手協(xié)議的格式為:

+-------+--------+----------------------
| 類型  | 長(zhǎng)度    | 內(nèi)容                   
+-------+--------+----------------------

我們可以從握手協(xié)議的數(shù)據(jù)包中得到這些信息:

  • 版本,TLS 1.2 也是 SSLv3.2。這是 SSL 客戶端能夠支持的 SSL 最高版本,主版本號(hào) 3,此版本號(hào) 2。TLS 目前的版本如下:

    Major Version Minor Version Version Type
    3 0 SSLv3
    3 1 TLS 1.0
    3 2 TLS 1.1
    3 3 TLS 1.2

    最后使用什么樣的版本,得由服務(wù)端決定。如果服務(wù)端不支持的話,客戶端得降版本。

  • 隨機(jī)數(shù) ,生成一個(gè)32字節(jié)隨機(jī)數(shù)。最后加密數(shù)據(jù)用的主密鑰,需要客戶端和服務(wù)端一起協(xié)商出來(lái)。后面服務(wù)端的 Server Hello 階段也會(huì)生成一個(gè)隨機(jī)數(shù)。一同用來(lái)計(jì)算出主密鑰。

    Random Bytes: 4e12e967b6169c4d67caf0575079f34b277d12318385f5a9...
    
  • 會(huì)話ID ,這里為 0。這個(gè) Session ID 是可以重用的,具體看服務(wù)端資源和支持情況。如果要復(fù)用 Session ID, SSL 服務(wù)端需要維護(hù)連接的狀態(tài)和上次握手成功留下的加密信息。因?yàn)檫@是這是第一次訪問(wèn)該網(wǎng)址,會(huì)話 ID 尚未創(chuàng)建,客戶端沒(méi)記錄,這里為 0。如果客戶端保存了 Session ID 的信息,下次發(fā)起 SSL 請(qǐng)求的時(shí)候會(huì)帶上。

  • 加密套件 ,客戶端可以支持的密碼套件列表。這些套件會(huì)根據(jù)優(yōu)先級(jí)排序。每一個(gè)套件代表一個(gè)密鑰規(guī)格。以 “TLS” 開頭,接著是密鑰交換算法,然后用 “WITH” 連接加密算法和認(rèn)證算法。一個(gè)加密套件有這么幾個(gè)內(nèi)容:密鑰交換算法、加密算法(會(huì)帶有支持的最高密鑰位數(shù))、認(rèn)證算法還有加密方式

    密鑰交換算法用在 SSL 握手階段的交換協(xié)商好的對(duì)稱密鑰的階段,為非對(duì)稱加密,比如:

    • EC Deffie-Hellman 密鑰交換算法。這里會(huì)被縮寫為 ECDHE,也稱為 DH 加密。
    • RSA 密鑰加密算法。

    加密算法,是最后要用來(lái)加密 HTTP 數(shù)據(jù)的,為對(duì)稱加密算法,比如:

    • DES
    • 3DES
    • AES

    摘要算法,也是對(duì)數(shù)據(jù)進(jìn)行摘要。后面可以用來(lái)做數(shù)據(jù)的校驗(yàn),保證數(shù)據(jù)的一致性,讓中途被篡改的包失效,比如:

    • MD5
    • SHA1
    • SHA256

    所以這里一共應(yīng)用了三種密鑰技術(shù),非對(duì)稱密鑰,對(duì)稱密鑰和摘要算法。用一句話總結(jié):用非對(duì)稱加密算法來(lái)傳遞對(duì)稱加密算法的密鑰,同時(shí)用摘要算法保證數(shù)據(jù)的完整性。

    這一次請(qǐng)求,客戶端提供了 20 種密碼套件供服務(wù)端選擇,最終使用什么密碼套件是服務(wù)端決定的。要什么密碼套件會(huì)在 Server Hello 中進(jìn)行反饋。

    Cipher Suites (20 suites)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
        Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
        Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
        Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
        Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
        Cipher Suite: TLS_ECDHE_ECDSA_WITH_RC4_128_SHA (0xc007)
        Cipher Suite: TLS_ECDHE_RSA_WITH_RC4_128_SHA (0xc011)
        Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
        Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
        Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
        Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
        Cipher Suite: TLS_RSA_WITH_RC4_128_SHA (0x0005)
        Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
    
  • 壓縮算法 ,這里為 0,說(shuō)明不支持壓縮算法
  • 擴(kuò)展字段 ,一些擴(kuò)展信息,比如 SNI 的支持,ALPN 的信息等等。

密碼套件隨著密碼學(xué)的發(fā)展而發(fā)展,而且根據(jù)現(xiàn)實(shí)應(yīng)用中,可能會(huì)有某些密碼被破解,從而導(dǎo)致密碼套件可能會(huì)導(dǎo)致安全問(wèn)題,所以一般都會(huì)使用當(dāng)前最新最安全的密碼套件。

在 Android 系統(tǒng)中,一般情況下,使用 SSLSocket進(jìn)行連接的時(shí)候,會(huì)帶上系統(tǒng)默認(rèn)的支持的密碼套件。但是這個(gè)有個(gè)缺點(diǎn),比如某些密碼套件的加密算法被破解或者出現(xiàn)安全漏洞,而且要跟著系統(tǒng)升級(jí)反應(yīng)緩慢。OkHttp 在進(jìn)行 SSL 握手的時(shí)候,會(huì)使用 ConnectionSpec 類中帶上提供了一系列最新的密碼套件??梢詮淖⑨屔峡矗@些密碼套件在 Chrome 51 和 Android 7.0 以上得到了完全支持。

OkHttp 密碼套件

然后,再把這些密碼套件和 Android 系統(tǒng)支持的密碼套件取交集,提交給服務(wù)端。這樣,萬(wàn)一哪個(gè)密碼套件有問(wèn)題,OkHttp 官方會(huì)下降支持。網(wǎng)絡(luò)庫(kù) OkHttp 庫(kù)會(huì)隨著版本的迭代,不斷地去提供比較新的密碼套件,并且放棄那些不安全的密碼套件。接入應(yīng)用即時(shí)更新 OkHttp,就不用等待緩慢的系統(tǒng)更新了。

如果提供的所有密碼套件服務(wù)端都不支持,OkHttp 有回退機(jī)制,退而求其次,選比較舊的套件。

2.3.3. 階段二

Server Hello

服務(wù)端收到了客戶端的 Hello,通過(guò)客戶端的配置信息,結(jié)合服務(wù)端的自身情況,給出了最終的配置信息。

Wireshark 解析后的內(nèi)容如下:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 93
        Handshake Protocol: Server Hello
            Handshake Type: Server Hello (2)
            Length: 89
            Version: TLS 1.2 (0x0303)
            Random
                GMT Unix Time: Jul  4, 2022 12:28:57.000000000 ?й???????
                Random Bytes: 6e15dfda5067399e9cd552ba30fb961914c5ce0e3f61d8f8...
            Session ID Length: 32
            Session ID: 7a92546002c514f9a0b11ef585935c7cc5182d9db3ef0db3...
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
            Compression Method: null (0)
            Extensions Length: 17
            Extension: server_name
            Extension: renegotiation_info
            Extension: ec_point_formats

具體內(nèi)容如下:

  • 版本,指定這次 SSL 使用 TLSv1.2 版本。

  • 隨機(jī)數(shù) ,上面的 Client Hello 過(guò)程也生產(chǎn)了一個(gè) 32 位隨機(jī)數(shù),這兩個(gè)隨機(jī)數(shù)將參與主密鑰(master key)的創(chuàng)建。

    Random Bytes: 6e15dfda5067399e9cd552ba30fb961914c5ce0e3f61d8f8...
    
  • 會(huì)話ID ,這里不為 0。說(shuō)明服務(wù)端允許客戶端再以后的 SSL 連接中復(fù)用這次會(huì)話。在使用 HTTPS 的 Session Ticket 可以用到。會(huì)話 ID 由服務(wù)端維持,采用恢復(fù)會(huì)話的方式創(chuàng)建 SSL 連接。

    Session ID: 7a92546002c514f9a0b11ef585935c7cc5182d9db3ef0db3...
    
  • 加密套件 ,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 。這個(gè)是從客戶端 Client Hello 上傳的 20 個(gè)加密套件中選中的,根據(jù)密碼套件的格式,上面的信息有,

    交換加密算法為ECDHE ,就是EC Diffie-Hellman ,RSA 表示后面 Server Key Exchange 階段的攜帶 DH 加密算法的公鑰的包的數(shù)字簽名的加密算法是 RSA。

    加密算法為 AES ,最高密鑰支持 128 位,使用 CBC 分組。

    認(rèn)證算法 SHA 。所謂 CBC 就是 AES 的機(jī)密模式,為分組加密。ECDHE_RSA,表示交換加密算法為 ,RSA 是后面的 獲取 ECDHE 的參數(shù)的包進(jìn)行的數(shù)字簽名用的算法。

  • 壓縮方法 ,這里為 0,表示不使用壓縮算法。

Certificate

上面的 Server Hello 已經(jīng)制定了接下來(lái)的非對(duì)稱加密算法

服務(wù)端下發(fā)證書,客戶端驗(yàn)證服務(wù)端的身份,并且取出證書攜帶的公鑰,這個(gè)公鑰是交換加密算法的公鑰。也就是在 Server Hello 階段指定的 ECDHE (EC Diffie-Hellman)算法,也是通常說(shuō)的 DH 加密。

這個(gè) Certificate 消息下發(fā)了從攜帶自己公鑰的數(shù)字證書和 CA 證書的證書鏈,在 Certificates 字段中:

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Certificate
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 2403
        Handshake Protocol: Certificate
            Handshake Type: Certificate (11)
            Length: 2399
            Certificates Length: 2396
            Certificates (2396 bytes)
                Certificate Length: 1283
                Certificate: 308204ff308203e7a0030201020210248b4dd17f3ef11a77... 
                Certificate Length: 1107
                Certificate: 3082044f30820337a0030201020203023a6f300d06092a86... 

CA 是 PKI 體系的重要組成部分,稱為認(rèn)證機(jī)構(gòu)。

那什么是 CA 證書?就是用來(lái) CA 中心發(fā)布的,認(rèn)證該服務(wù)單證書的合法性,可以確保該證書來(lái)源可靠而不是被中間人替換了。但是 CA 證書也可能被中間人攔截造假?那就再用一個(gè)證書來(lái)認(rèn)證它??雌饋?lái)好像沒(méi)完沒(méi)了。實(shí)際上到最后有一個(gè)根 CA 證書,這個(gè)證書存儲(chǔ)再瀏覽器或者操作系統(tǒng)中,是系統(tǒng)直接信任的。

服務(wù)端證書需要 CA 證書做認(rèn)證。使用的還是數(shù)字簽名方式,從數(shù)據(jù)中摘要一段信息,用 CA 證書的加密。然后驗(yàn)證的時(shí)候時(shí)候,用 CA 證書的公鑰解密,用同樣的摘要算法摘要數(shù)據(jù)部分和解密好的信息進(jìn)行比較。

證書的簽名和驗(yàn)簽

客戶端在驗(yàn)證服務(wù)端證書的有效性有這樣的一個(gè)過(guò)程。首先會(huì)找到該證書的認(rèn)證證書,也就是中級(jí) CA 證書。然后找中級(jí) CA 證書的認(rèn)證證書,可以是另一個(gè)中級(jí) CA 證書,也可能是根 CA 證書。這樣直到根 CA 證書。

接著從根 CA 證書開始往下去驗(yàn)證數(shù)字簽名。比如有這樣的證書鏈:根 CA 證書-> 中級(jí) CA 證書 -> 服務(wù)端證書。用 CA 證書的公鑰去驗(yàn)證中級(jí)證書的數(shù)字簽名,再用中級(jí)證書的公鑰去驗(yàn)證服務(wù)器證書的數(shù)字簽名。任何一個(gè)環(huán)節(jié)驗(yàn)證失敗,就可以認(rèn)為證書不合法。

這就是整個(gè)證書鏈的認(rèn)證過(guò)程:

證書驗(yàn)證過(guò)程

查看抓到的包的數(shù)據(jù),發(fā)現(xiàn)只有兩個(gè)證書。為服務(wù)端證書和中級(jí) CA 證書。根 CA 證書呢?順藤摸瓜找到它。

首先看服務(wù)端證書。它內(nèi)容如下:

Certificate: 308204ff308203e7a0030201020210248b4dd17f3ef11a77... 
    signedCertificate
        version: v3 (2)
        serialNumber: 0x248b4dd17f3ef11a7733fead4cd68c21
        signature (sha256WithRSAEncryption)
        issuer: rdnSequence (0)
            rdnSequence: 3 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-organizationName=GeoTrust Inc.)
                RDNSequence item: 1 item (id-at-commonName=GeoTrust SSL CA - G3)
        validity
            notBefore: utcTime (0)
                utcTime: 15-10-14 00:00:00 (UTC)
            notAfter: utcTime (0)
                utcTime: 17-12-30 23:59:59 (UTC)
        subject: rdnSequence (0)
            rdnSequence: 6 items
                RDNSequence item: 1 item (id-at-countryName=CN)
                RDNSequence item: 1 item (id-at-stateOrProvinceName=Zhejiang)
                RDNSequence item: 1 item (id-at-localityName=Hangzhou)
                RDNSequence item: 1 item (id-at-organizationName=NetEase (Hangzhou) Network Co., Ltd)
                RDNSequence item: 1 item (id-at-organizationalUnitName=MAIL Dept.)
                RDNSequence item: 1 item (id-at-commonName=*.163.com)
        subjectPublicKeyInfo
            algorithm (rsaEncryption)
            Padding: 0
            subjectPublicKey: 3082010a0282010100ce9da6fb3a940ae04a939b85a1a961...
        extensions: 8 items
            Extension (id-ce-subjectAltName)
            Extension (id-ce-basicConstraints)
            Extension (id-ce-keyUsage)
            Extension (id-ce-cRLDistributionPoints)
            Extension (id-ce-certificatePolicies)
            Extension (id-ce-extKeyUsage)
            Extension (id-ce-authorityKeyIdentifier)
            Extension (id-pe-authorityInfoAccessSyntax)
    algorithmIdentifier (sha256WithRSAEncryption)
    Padding: 0
    encrypted: ad75f99ff40e582bc9a17c01c98edf02696aa4f821dfe870...

從這個(gè)證書中我們可以窺見(jiàn)這些信息:

首先是 signedCertificate 字段的內(nèi)容,即數(shù)字證書的數(shù)據(jù):

  • 版本,version,v3。對(duì)應(yīng)的就是 X.509 V3 標(biāo)準(zhǔn)。

  • 序列號(hào) ,serialNumber,0x248...,證書頒發(fā)者唯一序列號(hào)。

  • 簽名算法ID ,Signature Algorithm。這里指的是使用 SHA-256 進(jìn)行摘要,RSA 進(jìn)行加密的簽名算法。

  • 證書頒發(fā)者 ,issuer,就是頒發(fā)該證書的 CA 的信息。里面攜帶后該 CA 的唯一名稱(DN,Distinguished Name),比如國(guó)家為 US(美國(guó)),組織機(jī)構(gòu)為 GeoTrust Inc.,名稱為 GeoTrust SSL CA - G3。后面我們需要從證書鏈找到該 CA 證書,去認(rèn)證當(dāng)前證書。

  • 有效期 ,validity,證書的起始時(shí)間和終止時(shí)間。可以得出該證書到 17 年 12 月 30 日后過(guò)期。

  • 對(duì)象名稱 ,subject,里面就是該證書的名稱等主要信息了。比如國(guó)家為 CN(中國(guó)),組織為 NetEase (Hangzhou) Network Co., Ltd。名稱為 *.163.com ,也是該證書適用的域名。

  • 對(duì)象公鑰信息 ,subjectPublicKeyInfo。因?yàn)檫@是服務(wù)端證書,這個(gè)公鑰后面將用于主密鑰的交換過(guò)程,從中可以了解到這個(gè)公鑰采用 RSA 加密,公鑰內(nèi)容為 3082010a0282010100ce9da6fb3a940ae04a939b85a1a961...

  • 擴(kuò)展部分 ,一些擴(kuò)展信息。比如對(duì)象的別名。這個(gè)如果是 CDN 的服務(wù)器證書,那么別名將會(huì)非常多。是所有使用該 CDN 的網(wǎng)站的域名。比如之前抓到的 CDNetworks 的 CDN 證書,它的擴(kuò)展字段 subjectAltName 有這些信息:

    Certificate: 308220a630821f8ea00302010202100b8a2d407d6121375c... 
        signedCertificate
            version: v3 (2)
            serialNumber: 0x0b8a2d407d6121375cba2fac96354a41
            signature (sha256WithRSAEncryption)
            issuer: rdnSequence (0)
            validity
            subject: rdnSequence (0)
                rdnSequence: 5 items
                    RDNSequence item: 1 item (id-at-countryName=US)
                    RDNSequence item: 1 item (id-at-stateOrProvinceName=California)
                    RDNSequence item: 1 item (id-at-localityName=Campbell)
                    RDNSequence item: 1 item (id-at-organizationName=CDNetworks Inc.)
                    RDNSequence item: 1 item (id-at-commonName=support13.cdnetworks.net)
            subjectPublicKeyInfo
            extensions: 10 items
                Extension (id-ce-authorityKeyIdentifier)
                Extension (id-ce-subjectKeyIdentifier)
                Extension (id-ce-subjectAltName)
                    Extension Id: 2.5.29.17 (id-ce-subjectAltName)
                    GeneralNames: 314 items
                        GeneralName: dNSName (2)
                            dNSName: support13.cdnetworks.net
                        GeneralName: dNSName (2)
                            dNSName: china.ray-ban.com
                        GeneralName: dNSName (2)
                            dNSName: static1.read.ru
                        GeneralName: dNSName (2)
                            dNSName: ps4.cache.square-enix.co.jp
                        ...
                Extension (id-ce-keyUsage)
                Extension (id-ce-extKeyUsage)
                Extension (id-ce-cRLDistributionPoints)
                Extension (id-ce-certificatePolicies)
                Extension (id-pe-authorityInfoAccessSyntax)
                Extension (id-ce-basicConstraints)
                Extension (iso.3.6.1.4.1.11129.2.4.2)
        algorithmIdentifier (sha256WithRSAEncryption)
        Padding: 0
        encrypted: 68728010fd9e4b7e3bdbe5e47ec680330b6851e1ea4dc737...
    
    

    可以了解到該 CDN 為 314 個(gè)域名提供服務(wù)。

然后是證書頒發(fā)機(jī)構(gòu)的簽名信息:

  • 簽名算法,algorithmIdentifier。這里得出使用的還是 SHA-256 摘要加 RSA 加密的簽名算法。這個(gè)就是認(rèn)證該證書的 CA 證書使用的簽名算法。
  • 簽名信息 ,encrypted,這個(gè)信息的內(nèi)容,CA 證書對(duì) SHA-256 對(duì)上面的數(shù)據(jù)部分進(jìn)行摘要后,使用 RSA 的私鑰加密獲得。后面會(huì)用在該證書的認(rèn)證過(guò)程,取出 CA 證書的公鑰,解密簽名信息,用同樣的算法獲取數(shù)據(jù)摘要,對(duì)比一下是否相同。

從上面的 issuer 可以了解到,認(rèn)證該服務(wù)器證書的 CA 證書為 GeoTrust SSL CA - G3 ,我們從 Certificates 找到對(duì)應(yīng)的中級(jí)證書的內(nèi)容如下(中級(jí)證書可以有好幾級(jí),我們這兒只有一級(jí)):

Certificate: 3082044f30820337a0030201020203023a6f300d06092a86... 
    signedCertificate
        version: v3 (2)
        serialNumber: 146031
        signature (sha256WithRSAEncryption)
        issuer: rdnSequence (0)
            rdnSequence: 3 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-organizationName=GeoTrust Inc.)
                RDNSequence item: 1 item (id-at-commonName=GeoTrust Global CA)
        validity
            notBefore: utcTime (0)
                utcTime: 13-11-05 21:36:50 (UTC)
            notAfter: utcTime (0)
                utcTime: 22-05-20 21:36:50 (UTC)
        subject: rdnSequence (0)
            rdnSequence: 3 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-organizationName=GeoTrust Inc.)
                RDNSequence item: 1 item (id-at-commonName=GeoTrust SSL CA - G3)
        subjectPublicKeyInfo
            algorithm (rsaEncryption)
            Padding: 0
            subjectPublicKey: 3082010a0282010100e3be7e0a86a3cf6b6d3d2ba197ad49...
        extensions: 8 items
            Extension (id-ce-authorityKeyIdentifier)
            Extension (id-ce-subjectKeyIdentifier)
            Extension (id-ce-basicConstraints)
            Extension (id-ce-keyUsage)
            Extension (id-ce-cRLDistributionPoints)
            Extension (id-pe-authorityInfoAccessSyntax)
            Extension (id-ce-certificatePolicies)
            Extension (id-ce-subjectAltName)
    algorithmIdentifier (sha256WithRSAEncryption)
    Padding: 0
    encrypted: a0d4f72cfb740b7f64f1cd436a9f62531c027c9890a2ee4f...

可以得到中級(jí)證書名為 GeoTrust SSL CA - G3 ,證書組織為 GeoTrust Inc. 。

認(rèn)證該 CA 證書的證書呢?還是看 issue 字段,認(rèn)證證書名為 GeoTrust Global CA ,組織同樣是 GeoTrust Inc.

其實(shí)這個(gè)就是根 CA 證書。在這個(gè)請(qǐng)求中沒(méi)有找到,但在瀏覽器或者操作系統(tǒng)可以找到。一般的瀏覽器和系統(tǒng)都會(huì)內(nèi)置該 CA 證書。所以根證書是受瀏覽器或者操作系統(tǒng)信任的,無(wú)需其他證書做擔(dān)保。

如果想要自己的系統(tǒng)再信任某些非通用的權(quán)威機(jī)構(gòu)的根 CA 證書,那么就去安裝它。

比如我的 Windows 系統(tǒng)就安裝了 GeoTrust Global CA 證書:

Windows 的證書管理

像我們平時(shí)使用 Charles 抓 HTTPS 就是這個(gè)原理,把 Charles 的 CA 證書安裝在手機(jī)中,成為受信任的根 CA 證書。

基本原理就是,Charles 代理作為 SSL 隧道,并沒(méi)有透明傳輸,而是作為一個(gè)中間人,攔截了 SSL 握手信息,修改里面的 CA 證書。仿冒手機(jī)端和真實(shí)服務(wù)端建立連接獲取主密鑰,然后又仿冒服務(wù)端和手機(jī)客戶端建立 SSL 連接,修改服務(wù)端證書的 CA 和數(shù)字簽名,這樣 Charles 就可以解析到加密的 HTTP 內(nèi)容了。

修改后的服務(wù)端證書如下,可以看到 issuer 被替換成了 Charles 的證書。

Certificate: 30821ff230821edaa0030201020206015e7406ab1c300d06... 
    signedCertificate
        version: v3 (2)
        serialNumber: 1505185147676
        signature (sha256WithRSAEncryption)
        issuer: rdnSequence (0)
            rdnSequence: 6 items
                RDNSequence item: 1 item (id-at-commonName=Charles Proxy Custom Root Certificate)
                RDNSequence item: 1 item (id-at-organizationalUnitName=http://charlesproxy.com/ssl)
                RDNSequence item: 1 item (id-at-organizationName=XK72 Ltd)
                RDNSequence item: 1 item (id-at-localityName=Auckland)
                RDNSequence item: 1 item (id-at-stateOrProvinceName=Auckland)
                RDNSequence item: 1 item (id-at-countryName=NZ)
        validity
        subject: rdnSequence (0)
            rdnSequence: 5 items
                RDNSequence item: 1 item (id-at-countryName=US)
                RDNSequence item: 1 item (id-at-stateOrProvinceName=California)
                RDNSequence item: 1 item (id-at-localityName=Campbell)
                RDNSequence item: 1 item (id-at-organizationName=CDNetworks Inc.)
                RDNSequence item: 1 item (id-at-commonName=support13.cdnetworks.net)
        subjectPublicKeyInfo
        extensions: 7 items
    algorithmIdentifier (sha256WithRSAEncryption)
    Padding: 0
    encrypted: da491fc58682c7b85751db9def0b366d58cf09755ab8ef7d...

到這個(gè)階段,我們有了一個(gè)小想法,是不是可以自己搞個(gè)根 CA ,然后推廣到各個(gè)設(shè)備上使用?

理論上可以。但是推廣成本太高,市場(chǎng)上被大多數(shù)系統(tǒng)認(rèn)可的就這幾家機(jī)構(gòu):

  • Symantec(VeriSign/GeoTrust)
  • Comodo
  • GoDaddy

像 BAT 這樣的大廠也需要買它們的證書。像我這次抓的是網(wǎng)易的包,使用的也是 GeoTrust 。不過(guò)也有例外,我們的 12306 比較任性,就沒(méi)有購(gòu)買這些機(jī)構(gòu)的證書,所以上這個(gè)網(wǎng)站在 Chrome 等瀏覽器經(jīng)常會(huì)彈出不受信任等等。

Server Key Exchange

密鑰交換階段,這個(gè)步驟是可選步驟,對(duì) Certificate 階段的補(bǔ)充,只有在這幾個(gè)場(chǎng)景存在:

  • 協(xié)商采用了 RSA 加密,但是服務(wù)端證書沒(méi)有提供 RSA 公鑰。
  • 協(xié)商采用了 DH(EC Diffie-Hellman) 加密,但是服務(wù)端證書沒(méi)有提供 DH 參數(shù)。
  • 協(xié)商采用 fortezza_kea 加密,但是服務(wù)端證書沒(méi)有提供參數(shù)。

我們滿足了哪一個(gè)場(chǎng)景?

可以知道我們前面協(xié)商了使用 EC Diffie-Hellman 算法,而且沒(méi)帶參數(shù),所以這個(gè)包就是服務(wù)端帶過(guò)來(lái)的用來(lái)協(xié)商 DH 密鑰參數(shù)的。

TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 333
    Handshake Protocol: Server Key Exchange
        Handshake Type: Server Key Exchange (12)
        Length: 329
        EC Diffie-Hellman Server Params
            Curve Type: named_curve (0x03)
            Named Curve: secp256r1 (0x0017)
            Pubkey Length: 65
            Pubkey: 04a10ad7a23135095205caf7ca8e4c838728e877dbcb23c3...
            Signature Hash Algorithm: 0x0601
                Signature Hash Algorithm Hash: SHA512 (6)
                Signature Hash Algorithm Signature: RSA (1)
            Signature Length: 256
            Signature: 8c7c51f60574144e9e1385a534e12f85911e8dc7cd40dc04...

這個(gè)包把 DH 算法需要的公鑰給傳遞過(guò)來(lái)了,即 Pubkey: 04a10ad7a23135095205caf7ca8e4c838728e877dbcb23c3...

同樣這個(gè)包也攜帶了數(shù)字簽名 Signature: 8c7c51f60574144e9e1385a534e12f85911e8dc7cd40dc04... ,用服務(wù)端證書帶過(guò)來(lái)的公鑰驗(yàn)證一下完整性和來(lái)源。

Server Hello Done

通知客戶端,版本和加密套件協(xié)商結(jié)束。

TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 4
    Handshake Protocol: Server Hello Done
        Handshake Type: Server Hello Done (14)
        Length: 0

這個(gè) Server Hello Done,就像 TCP 協(xié)議的 ACK 確認(rèn)包一樣,這里服務(wù)端也給了個(gè)確認(rèn)的信息,通知客戶端已經(jīng)做好進(jìn)入下一個(gè)階段的準(zhǔn)備。

通過(guò) Wireshark 抓包發(fā)現(xiàn)了一個(gè)現(xiàn)象,就是 Server Key Exchange 和 Server Hello Done 被放到了同一個(gè) SSL 記錄協(xié)議中,這是因?yàn)?SSL 記錄協(xié)議具有組合功能??蛻舳耸盏竭@樣的包后,會(huì)處理成兩個(gè)單獨(dú)的協(xié)議包,這又是 SSL 記錄協(xié)議的分組功能。

Secure Sockets Layer
    TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done

這樣做的好處,可以減少發(fā) TCP 包的次數(shù),減少 SSL 握手的時(shí)間。

2.3.4. 階段三

如果在一些安全級(jí)別高的場(chǎng)景,服務(wù)端也會(huì)要求客戶端上報(bào)證書,會(huì)有 Certificate Request 的 SSL 握手報(bào)文。這樣的情況下,接下來(lái)會(huì)有完整的客戶端證書上報(bào)服務(wù)端的流程。整個(gè)流程和階段二類似。

2.3.5. 階段四

因?yàn)槲覀冞@里只需要驗(yàn)證服務(wù)端的證書,所以直接進(jìn)入階段四,開始最后的握手。這個(gè)階段的主要目的,就是生產(chǎn)加密密鑰,并進(jìn)行安全傳輸。

Client Key Exchange

這里,客戶端不直接生成加密密鑰,而是通過(guò)之前客戶端和服務(wù)端生成的隨機(jī)數(shù)又再生成一個(gè)隨機(jī)數(shù),使用前面協(xié)商好的用 EC Diffie-Hellman 算法進(jìn)行加密傳輸給服務(wù)端。這個(gè)值又被稱為 “premaster secret“。

TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 70
    Handshake Protocol: Client Key Exchange
        Handshake Type: Client Key Exchange (16)
        Length: 66
        EC Diffie-Hellman Client Params
            Pubkey Length: 65
            Pubkey: 0433cfbd121d0fa5299819604a15237fc9359845a2a9dffe...

服務(wù)端收到這個(gè)報(bào)文后,會(huì)使用自己的私鑰解開這個(gè)隨機(jī)數(shù)。

在這個(gè)階段過(guò)后,服務(wù)端和客戶端都有三個(gè)隨機(jī)數(shù):客戶端隨機(jī)數(shù)、服務(wù)端隨機(jī)數(shù)和預(yù)備主密鑰。

在服務(wù)端收到了 Client Key Exchange 消息后,兩端都按照相應(yīng)的算法生成了主密鑰,加密密鑰交換完成。

交換完了,因?yàn)橹髅荑€是兩個(gè)端按照約定好的算法產(chǎn)生的,如何保證這個(gè)主密鑰是正確的?

這時(shí)候會(huì)進(jìn)入下一個(gè)階段??蛻舳撕头?wù)端會(huì)對(duì)握手信息使用 SHA 做個(gè)摘要,用 AES 加密算法和主密鑰加密,傳遞給對(duì)方驗(yàn)證。這種方式也稱為消息認(rèn)證。就是下面的過(guò)程:

Change Cipher Spec(Client)

客戶端通知服務(wù)端,后續(xù)的報(bào)文將會(huì)被加密。

Encrypted Handshake Message(Client)

這里就是客戶端的 Client Finished 消息。

也是整個(gè) SSL 過(guò)程中,發(fā)送給服務(wù)端的第一個(gè)加密消息。

服務(wù)端接收后,服務(wù)端用同樣的方式計(jì)算出已交互的握手消息的摘要,與用主密鑰解密后的消息進(jìn)行對(duì)比,一致的話,說(shuō)明兩端生成的主密鑰一致,完成了密鑰交換。

Change Cipher Spec(Server)

服務(wù)端通知客戶端,后續(xù)的報(bào)文將會(huì)被加密。

Encrypted Handshake Message(Server)

這里就是服務(wù)端的 Server Finish 消息。

和上面的客戶端的 Encrypted Handshake Message 一樣,是服務(wù)端發(fā)出的第一條加密信息。

客戶端按照協(xié)商好的主密鑰解密并驗(yàn)證正確后,SSL 握手階段完成。

2.3.6. 小結(jié)

整個(gè) SSL 握手主要是要完成這幾個(gè)目標(biāo):

  • 對(duì)服務(wù)端身份的驗(yàn)證,或者客戶端
  • 協(xié)商好對(duì)稱加密算法和對(duì)稱加密密鑰

對(duì)應(yīng) Java API 為 SSLSocket :

sslSocket.startHandshake();

這次請(qǐng)求的整個(gè)過(guò)程耗時(shí)大約為 380ms??梢钥闯?,SSL 握手是很消耗請(qǐng)求時(shí)間的。所以對(duì)握手進(jìn)行優(yōu)化,比如使用 Session ID 或者 Session Ticket。這個(gè)類似于 HTTP 協(xié)議的 Session 和 Cookie 的使用。

2.4. 數(shù)據(jù)傳輸

經(jīng)過(guò)了 SSL 握手后,服務(wù)端的身份認(rèn)證成功,協(xié)商出了加密算法為 AES,密鑰為 xxxxx(客戶端和服務(wù)端拿三個(gè)隨機(jī)值用相同算法計(jì)算出來(lái)的,并沒(méi)有明文傳輸)。一切準(zhǔn)備就緒。

SSL 握手成功,已經(jīng)可以對(duì)接下來(lái)的數(shù)據(jù)加密了,接下來(lái)各種應(yīng)用層協(xié)議都可以加密傳輸。

2.4.1. Application Data

應(yīng)用數(shù)據(jù)傳輸消息。因?yàn)檫@里是 HTTPS,所以可以對(duì) HTTP 應(yīng)用協(xié)議數(shù)據(jù)加密然后傳輸了。

Secure Sockets Layer
    TLSv1.2 Record Layer: Application Data Protocol: http
        Content Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 1072
        Encrypted Application Data: 6d9b3c9089271630c33506fe28cd6a61fed1f4bd2808f537...

從這里,不知道密鑰是無(wú)法知道這里傳輸?shù)氖鞘裁磾?shù)據(jù),連傳輸?shù)氖鞘裁磪f(xié)議的內(nèi)容都不知道。

所以之前創(chuàng)建 SSL 隧道,讓代理服務(wù)器盲傳 HTTPS 數(shù)據(jù),就得通過(guò) CONNECT 方法告訴代理服務(wù)器要連哪臺(tái)主機(jī),哪個(gè)端口號(hào),要不然代理服務(wù)器也是一臉懵逼。

所以 SSL 協(xié)議是很獨(dú)立的,這里是對(duì) HTTP 進(jìn)行了加密,也可以對(duì)其他協(xié)議進(jìn)行加密。它就像是 TCP 和應(yīng)用層協(xié)議的中間層,為上層協(xié)議提供了加密的數(shù)據(jù)傳輸。

2.4.2. Encryted Alert

SSL 警告消息,因?yàn)槭羌用艿膬?nèi)容,所以單從 Wireshark 看不出警報(bào)的內(nèi)容。

Secure Sockets Layer
    TLSv1.2 Record Layer: Encrypted Alert
        Content Type: Alert (21)
        Version: TLS 1.2 (0x0303)
        Length: 48
        Alert Message: Encrypted Alert

但因?yàn)榫瘓?bào)消息經(jīng)常只是客戶端用來(lái)提示服務(wù)端 SSL 傳輸結(jié)束,對(duì)照抓包到的內(nèi)容確實(shí)如此。所以這里只是 SSL 傳輸結(jié)束的一個(gè)信號(hào)。

發(fā)出了 Encryted Alert 后客戶端數(shù)據(jù)傳輸完畢,準(zhǔn)備進(jìn)入四次揮手?jǐn)嚅_ TCP 連接。

2.5. 四次揮手

客戶端發(fā)送完 HTTP 的數(shù)據(jù),也正確地獲取到服務(wù)端的響應(yīng)。完成了 HTTPS 的請(qǐng)求工作后,接下來(lái)要關(guān)閉 TCP 連接。關(guān)閉 TCP 連接一共分成四步,也可以成為四次揮手。對(duì)應(yīng)包如下:

No. Time Source Destionation Protocol Length Info
688 7.607349 172.17.32.211 172.17.32.19 TCP 66 35973 → 8888 [FIN, ACK] Seq=1657 Ack=3213 Win=96512 Len=0 TSval=15986483 TSecr=59355534
689 7.607363 172.17.32.19 172.17.32.211 TCP 66 8888 → 35973 [ACK] Seq=3213 Ack=1658 Win=65024 Len=0 TSval=59355763 TSecr=15986483
690 7.620494 172.17.32.19 172.17.32.211 TCP 66 8888 → 35973 [FIN, ACK] Seq=3213 Ack=1658 Win=65024 Len=0 TSval=59355764 TSecr=15986483
697 7.661600 172.17.32.211 172.17.32.19 TCP 66 35973 → 8888 [ACK] Seq=1658 Ack=3214 Win=96512 Len=0 TSval=15986494 TSecr=59355764

可以看到,這四個(gè)包都只有 66 個(gè)字節(jié)。因?yàn)椴粠?shù)據(jù),是純粹的 TCP 首部。

2.5.1. Round 1

客戶端 A 發(fā)出 FIN + ACK 包,通知服務(wù)端數(shù)據(jù)傳輸結(jié)束,可以關(guān)閉連接了。同樣這是一個(gè) ACK 確認(rèn)包,指出希望的下一個(gè)包的序號(hào)為 3213。

這個(gè)階段后,客戶端進(jìn)入 FIN_WAIT_1 狀態(tài),不再發(fā)送數(shù)據(jù)給服務(wù)端,但是如果服務(wù)端還在傳數(shù)據(jù)過(guò)來(lái),客戶端的 ACK 確認(rèn)報(bào)文還會(huì)有。

服務(wù)端進(jìn)入 CLOSE_WAIT 狀態(tài)。這個(gè)狀態(tài)再發(fā)出 ACK 確認(rèn)包后解除。

2.5.2. Round 2

接收端 B 收到第一次揮手的包后,會(huì)先給一個(gè) ACK 確認(rèn)包,為第二次揮手。

這里有個(gè)疑問(wèn),既然收到了 A 的結(jié)束信息,為什么不馬上結(jié)束呢?因?yàn)?A 完成數(shù)據(jù)傳輸,但是 B 可能還有數(shù)據(jù)沒(méi)有傳完,所以比三次握手會(huì)多一個(gè)步驟。

收到客戶端的 FIN 包后,已經(jīng)知道客戶端結(jié)束數(shù)據(jù)傳輸了,所以服務(wù)端后面數(shù)據(jù)傳輸結(jié)束,就可以直接通知客戶端可以結(jié)束了。

客戶端收到 ACK 確認(rèn)包后,進(jìn)入 FIN_WAIT_2 狀態(tài)。

2.5.3. Round 3

如果服務(wù)端數(shù)據(jù)還沒(méi)有傳完,會(huì)繼續(xù)傳給客戶端。

等服務(wù)端的數(shù)據(jù)完全傳完后,會(huì)再發(fā)一個(gè) FIN + ACK 包,通知客戶端數(shù)據(jù)傳完了。

這個(gè)階段后,服務(wù)端進(jìn)入 LAST_ACK 狀態(tài),即等待客戶端最后一個(gè) ACK 報(bào)文。

2.5.4. Round 4

發(fā)送端 A 收到 B 發(fā)出的 FIN + ACK 后,進(jìn)入 TIME_WAIT 狀態(tài)。服務(wù)端收到 FIN 后進(jìn)入 CLOSED 狀態(tài)關(guān)閉連接。

經(jīng)過(guò) 2MSL 時(shí)間,沒(méi)有問(wèn)題后會(huì)關(guān)閉連接。也進(jìn)入 CLOSED 狀態(tài)。

為什么有個(gè) TIME_WAIT

原因是有可能服務(wù)端一直沒(méi)有收到 FIN + ACK,有可能觸發(fā)超時(shí)重傳,又發(fā)了一個(gè) FIN 給客戶端,客戶端要重新發(fā)送最后一個(gè)包。

2.5.5. 小結(jié)

TCP 四次揮手的時(shí)序圖如下:

四次揮手時(shí)序圖

3. 擴(kuò)展

3.1. Session ID 和 Session Ticket

3.2. SNI(Server Name Indication)

3.3. ALPN(Application Layer Protocol Negotiation)

4. 資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

  • 原文地址 http://blog.csdn.net/u012409247/article/details/4985...
    0fbf551ff6fb閱讀 3,696評(píng)論 0 13
  • 其實(shí),我對(duì)https以前只有一個(gè)大概的了解,最近工作中遇到一個(gè)問(wèn)題從而將https協(xié)議做了一個(gè)徹底的學(xué)習(xí)和認(rèn)知,下...
    你飛躍俊杰閱讀 908評(píng)論 0 2
  • 其實(shí),我對(duì)https以前只有一個(gè)大概的了解,最近工作中遇到一個(gè)問(wèn)題從而將https協(xié)議做了一個(gè)徹底的學(xué)習(xí)和認(rèn)知,下...
    一條魚的星辰大海閱讀 3,546評(píng)論 0 1
  • 畢業(yè)在即,2018年的6月我就要步入社會(huì)了。 嘗試過(guò)考研,并還付諸了努力和準(zhǔn)備,最后我向現(xiàn)實(shí)低頭認(rèn)輸,不管所謂的現(xiàn)...
    我的城堡閱讀 371評(píng)論 0 0
  • 我滿懷著期待,你的到來(lái)。當(dāng)你來(lái)時(shí),已經(jīng)離去。 很多人的忙碌,春光中忙著為夏日炎炎做著無(wú)畏的掙扎,而...
    半道殘陽(yáng)鋪水中閱讀 323評(píng)論 1 2

友情鏈接更多精彩內(nèi)容