最近的開發調試過程中涉及到了HTTPS發送與接收,遇到實際問題才發現對這部分尚屬于一知半解。結合實際問題的解決過程來詳細整理以下HTTPS通信過程。
需要調試的功能為BMC作為客戶端向搭建好的Web服務器發送HTTPS請求,Web服務器負責接收處理發送過來的HTTPS請求。BMC的IP為100.6.100.224,Web服務器的IP為100.2.74.71。在BMC向Web服務器發送一條請求HTTPS請求,服務器成功接收到請求,返回成功信息。通過WireShark抓包這一過程,如下圖所示:
從中可以看出,HTTPS通信過程分為兩部分,首先進行TCP握手,然后進行TLS握手并發送信息。
1.1 TCP三次握手
前三個Wireshark數據包展示的就是TCP三次握手的過程,如下圖所示:
1.1.1 第一次握手
第一次握手,客戶端向服務器端發送SYN標志置位的報文,同時生成自己的隨機初始序列號seq。數據包如下圖所示。(這里客戶端使用的seq直接使用了0,不太清楚為什么不是隨機數)
1.1.2 第二次握手
第二次握手,服務器端向客戶端發送SYN與ACK置位的報文,生成服務器端的隨機初始序列號seq(這里服務器端的seq也直接使用了0),可以看到回復的報文中Ack的值為1(客戶端seq+1),表示已收到客戶端的SYN。
1.1.3 第三次握手
第三次握手,客戶端向服務器端發送ACK置位的報文,報文中Ack的值為1(服務器端seq+1),服務器端收到后TCP連接就成功建立了。
1.2 TLS握手
TCP連接建立后,開始進入TLS握手階段。TLS握手階段數據包如下所示:
1.2.1 Client Hello
首先客戶端向服務器端發送初始消息,內容包括支持的 TLS 版本,客戶端隨機數(Client Random,用于后續密鑰生成)與支持的加密套件列表等,如下圖所示。
1.2.2 Server Hello
服務器端會回復這一消息,如下圖所示,回復的消息中包括選定的 TLS 版本(與客戶端支持的版本一致),服務器隨機數(Server Random,用于后續密鑰生成)與選擇的加密套件(從客戶端發送的列表中選擇),從圖中可以看出服務器端選擇了TLS v1.2,加密套件為TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
1.2.3 Certificate,Serverkey Exchange,Server Hello Done
下圖的數據包中包括了Certificat,Serverkey Exchange與Server Hello Done三部分信息。服務器端發送其數字證書,包含服務器的公鑰、證書頒發機構(CA)的簽名以及域名等信息,供客戶端驗證身份,客戶端則會驗證證書是否由可信 CA 頒發、證書是否過期或被吊銷以及證書中的域名與實際訪問的域名是否一致。如下圖所示,可以看到數據包中包含了證書信息
視選擇的加密套件需要,服務器還會發送密鑰交換參數(如 ECDHE 的公鑰參數)以及用服務器私鑰簽名的數據(確保參數未被篡改):
最后服務器端還通知客戶端,協商部分結束:
1.2.4 Client Key Exchange,Change Cipher Spec,Encrypted HandShake Message
客戶端會生成一個預主密鑰(pre-master secret),預主密鑰用服務器的公鑰加密后會被發送給服務器端。服務器會使用其私鑰解密這個預主密鑰,從而獲得客戶端的預主密鑰。雙方都擁有預主密鑰之后,會使用之前的兩個隨機數(Client Hello中的Random與Server Hello中的Random)生成主密鑰。到這里還沒結束,TLS協議會使用PRF(偽隨機函數)來從主密鑰派生出一個用于加密的會話密鑰和一個用于消息完整性和認證的MAC密鑰。所有的密鑰被正確生成和派生之后,客戶端和服務器會通過交換完成的消息來確認彼此的身份,并確保所有的握手參數都是一致的,到此握手階段才算完成。
1.2.5 Application Data, FIN
完成握手后,客戶端就開始向服務器端發送數據。從數據包中可以看到,正常發送完畢之后,服務器端發送FIN標志置位的數據包斷開連接,連接最后被斷開了。