本文談談我的看法,主要分為以下幾個方面:
- HTTPS 協議是什么?
-
HTTPS 是如何工作的?
-
HTTPS 真的安全嗎?
一、什么是 HTTPS
HTTPS,也稱作 HTTP over TLS,TLS 前身是 SSL,會有各個版本。TLS 協議在 TCP/IP 協議棧中的關系如下:

上圖描述了在 TCP/IP 協議棧中 TLS(各子協議)和 HTTP 的關系,HTTP+TLS 也就是 HTTPS。和 HTTP 相比,HTTPS 的優勢:
- 數據完整性:內容傳輸經過完整性校驗。
- 數據隱私性:內容經過對稱加密,每個連接生成一個唯一的加密密鑰。
- 身份認證:第三方無法偽造服務端(客戶端)身份。
二、HTTPS如何工作的
1、工作流程
如下圖所示,就是HTTPS協議的工作流程。

2、TCP三次握手
首先是TCP協議的三次握手,如下圖所示:

- Step1:客戶端發送一個SYN=1,ACK=0標志的數據包給服務端,請求進行連接,這是第一次握手;
- Step2:服務端收到請求并且允許連接的話,就會發送一個SYN=1,ACK=1標志的數據包給發送端,告訴它,可以通訊了,并且讓客戶端發送一個確認數據包,這是第二次握手;
- Step3:服務端發送一個SYN=0,ACK=1的數據包給客戶端端,告訴它連接已被確認,這就是第三次握手。TCP連接建立,開始通訊。
我們通過wireshark抓包查看三次握手過程:
- Step1:啟動wireshark抓包,打開瀏覽器輸入www.huawei.com。
- Step2:使用ping www.huawei.com獲取IP。
通過wireshark抓包,首先我們測試用www.huawei.com,先ping 網址得到IP。

- Step3:輸入過濾條件獲取待分析數據包列表 ip.addr == 113.96.132.64。

圖中可以看到wireshark截獲到了三次握手的三個數據包。第四個包才是HTTPS的Client Hello, 這說明HTTP的確是使用TCP建立連接的。
第一次握手數據包
客戶端發送一個TCP,標志位為SYN,序列號為0, 代表客戶端請求建立連接。 如下圖。

數據包的關鍵屬性如下:
- SYN :標志位,表示請求建立連接
- Seq = 0 :初始建立連接值為0,數據包的相對序列號從0開始,表示當前還沒有發送數據
- Ack =0:初始建立連接值為0,已經收到包的數量,表示當前沒有接收到數據
第二次握手的數據包
服務器發回確認包, 標志位為 SYN,ACK. 將確認序號(Acknowledgement Number)設置為客戶的I S N加1以.即0+1=1, 如下圖:

數據包的關鍵屬性如下:
- [SYN + ACK]: 標志位,同意建立連接,并回送SYN+ACK。
- Seq = 0 :初始建立值為0,表示當前還沒有發送數據
- Ack = 1:表示當前端成功接收的數據位數,雖然客戶端沒有發送任何有效數據,確認號還是被加1,因為包含SYN或FIN標志位。(并不會對有效數據的計數產生影響,因為含有SYN或FIN標志位的包并不攜帶有效數據)
第三次握手的數據包
客戶端再次發送確認包(ACK) SYN標志位為0,ACK標志位為1.并且把服務器發來ACK的序號字段+1,放在確定字段中發送給對方.并且在數據段放寫ISN的+1, 如下圖:

數據包的關鍵屬性如下:
- ACK :標志位,表示已經收到記錄
- Seq = 1 :表示當前已經發送1個數據
- Ack = 1 : 表示當前端成功接收的數據位數,雖然服務端沒有發送任何有效數據,確認號還是被加1,因為包含SYN或FIN標志位(并不會對有效數據的計數產生影響,因為含有SYN或FIN標志位的包并不攜帶有效數據)。
就這樣通過了TCP三次握手,建立了連接。
3、HTTPS握手
3.1、客戶端發起Client Hello握手
Client Hello握手
我們以抓博客園www.rzrgm.cn為例,可以看到一個Client Hello握手,我們可以看到客戶端握手發起了了一個握手類型為Client Hello的握手(Handshake Type:Client Hello),同時附帶了這么一些信息:
- Random1(隨機數)和一個時間戳。
- 客戶端支持的加密協議套裝。告訴 HTTPS 的服務器端,客戶端能支持下面這 32 種加密協議套裝中列出的算法,讓服務器選擇一個加密協議算法套裝。
- 客戶端支持的簽名算法,讓服務器端自由選擇一個用于后續的加密通信。
- 訪問的 Web 服務器的信息。
3.2、服務端收到Client Hello握手并發起Server Hello握手并下發證書
Server ACK回應
在客戶端發送Client Hello握手后,服務端會回應ACK信息,如下圖所示:

接下來HTTPS 服務器馬上給客戶端回復了下面這 4 條 SSL 握手信息。
- Server Hello
- Certificate
- Server Key Exchange Server
- Hello Done
Sever Hello握手
服務端也會發一串隨機數Random2,并告訴客戶端,服務器端準備選擇TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256作為秘鑰交互的加密協議套裝,該加密協議的套裝名字肯定出現在客戶端發送給服務器的支持的 32 個列表中。

Certificate證書
SSL 服務器證書信息。在這條 HTTPS 服務器給客戶端回復消息 SSL 握手信息里面,其還會把服務器端的 SSL 證書發送給客戶端,從圖中的轉包信息中,我們能清晰地發現服務器端 SSL 證書的相關信息。
需要注意的是,如果是 SSL 的雙向認證,服務器端也可以要求客戶端把 SSL 證書發送給服務器端(對應的 SSL 握手消息名稱為:CertificateRequest),這個時候,客戶端就會把其 SSL 證書發送給服務器端,從而證明其就是服務器端信任的客戶端。

Server Key Exchange Server以及Server Hello Done
如下圖所示,HTTPS 服務器告訴了客戶端其將會采用的 EC Diffie-Hellman 算法進行 HTTPS 服務器和客戶端的秘鑰交換,并提供了 EC Diffie-Hellman 算法使用到的服務器端的參數:
- 曲線類型:named_curve: x25519
- 公鑰信息:Pubkey
- 簽名的算法:rsa_pkcs1_sha256
- 簽名的信息:signature

3.3、客戶端完成密鑰交換并發起加密傳輸請求
當客戶端收到服務器端的相關公鑰信息、SSL 證書以及摘要算法和摘要信息后,會發送一個ack告訴服務端已經收到hello數據包以及證書。
此時客戶端需要驗證服務器發過來的證書的合法性:通過操作系統內置的ca證書,來驗證服務器證書的頒發者和過期時間是否合法,如果存在數據簽名,則用操作系統中頒發者CA的公鑰對簽名解密,用相同的hash算法算出簽名的hash值,將這個hash值與簽名中的hash值對比。驗證是否是真實的服務器發送的。然后客戶端會響應下面3 條 SSL 握手信息:
- Client Key Exchange
- Change Cipher Spec
- Encrypted Handshake Message
Client Key Exchange 握手信息
客戶端驗證通過,取出證書中的公鑰,然后再生成一個隨機數random3,用這個公鑰對random3加密,生成PreMaster Key,客戶端根據服務器傳來的公鑰生成了 PreMaster Key,Client Key Exchange 就是將這個 key 傳給服務端,服務端再用自己的私鑰解出這個 PreMaster Key 得到客戶端生成的 Random3。至此,客戶端和服務端都擁有 Random1 + Random2 + Random3,兩邊再根據同樣的算法就可以生成一份秘鑰,握手結束后的應用層數據都是使用這個秘鑰進行對稱加密。為什么要使用三個隨機數呢?這是因為 SSL/TLS 握手過程的數據都是明文傳輸的,并且多個隨機數種子來生成秘鑰不容易被暴力破解出來。
根據PreMaster Key,服務器和客戶端會計算出相同的主密碼(Master secret),然后根據主密碼生成下面的比特序列(秘鑰素材)。
- 對稱密碼的秘鑰
- 消息認證碼的秘鑰
- 對稱密碼的 CBC 模式中使用的初始化向量(IV)
需要注意的是,Client 秘鑰交換的方式主要有兩種:
- 通過 RSA 公鑰密碼交換秘鑰:這個時候客戶端會在發送 ClientKeyExchange 消息時,將經過加密的預備主密碼一起發送給服務器。
- 使用 Diffie-Hellman 交換秘鑰:客戶端會在發送 ClientKeyExchange 消息時,將 Diffie-Hellman 公開值(Pub Key)一起發送給服務器,根據這個值,客戶端和服務器會各自生成預備主密碼,而且更加這個預備主密碼能夠生成相同的對稱主密碼。

Change Cipher Spec
Change Cipher Spec握手信息就是告訴服務端,要換密碼了。

Encrypted Handshake Message
客戶端發出使用主密碼加密的結束信息,告訴服務器端:“秘鑰交換握手協議到此結束”。

3.4、服務端也告知客戶端進行加密傳輸
然后HTTPS 服務端馬上給客戶端回復 2 條 SSL 握手信息,這時輪到服務器端發送“Change Cipher Spec”消息了,服務器告訴客戶端:“好,現在我也要切換密碼了”。服務器端用預備主密碼(Pre-Master secret)計算出的主秘鑰加密了一條信息,并發送給客戶端:“好的,秘鑰交換握手協議到此結束”。如果通信雙方都能把結束消息解密成功,說明主秘鑰已經交換成功。就可以發送真正的用主密碼加密的應用數據的信息了。

3.5、開始進行數據加密傳輸
服務端就可以用對稱秘鑰把加密過的 HTML 網頁內容發送給客戶端了,如下圖所示:

上面的步驟只是把我當前環境下抓取到的使用 TL S1.2 協議規范進行了 HTTPS 通信原理和過程的梳理和解釋,在不同的環境下,其通信過程會有一些差異,比如,如果配置了雙向 SSL 認證,其 SSL 服務器端還會要求客戶端把客戶端的證書發送到服務端,從而驗證客戶端是否是可信任的,另外在進行主密碼交換的過程中,也可能采用 RSA 公鑰密碼,而不是 Diffie-Hellman,此時,其 SSL 握手消息會有所不同,但是整體的流程和交互過程思路基本上保持相同。
三、HTTPS真的安全么
HTTPS 真的完全安全嗎?連訪問的域名都獲取不到?答案是否定的。上述 HTTPS 在握手階段有一個很重要的東西:證書。
1、SNI:域名裸奔
當訪問 HTTPS 站點時,會首先與服務器建立 SSL 連接,第一步就是請求服務器的證書。
當一個 Server IP 只對應一個域名(站點)時,很方便,任意客戶端請求過來,無腦返回該域名(服務)對應的證書即可。但 IP 地址(IPv4)是有限的呀,多個域名復用同一個 IP 地址的時候怎么辦?服務器在發送證書時,不知道瀏覽器訪問的是哪個域名,所以不能根據不同域名發送不同的證書。因此 TLS 協議升級了,多了 SNI 這個東西,SNI 即 Server Name Indication,是為了解決一個服務器使用多個域名和證書的 SSL/TLS 擴展。現在主流客戶端都支持這個協議的。
它的原理是:在與服務器建立 SSL 連接之前,先發送要訪問站點的域名(Hostname),這樣服務器會根據這個域名返回一個合適的證書。此時還沒有辦法進行加解密,因此至少這個域名是裸奔的。如下圖所示,訪問博客園在進行Client Hello握手時就會帶上需要訪問的域名:

2、中間人攻擊
HTTPS 中的關鍵其實在于這個證書。中間人攻擊就是在客戶端、服務器之間多了個『中介』,『中介』在客戶端、服務器雙方中偽裝對方。如下所示這個『MitmProxy』充當了中間人:
然后訪問網站時,會出現瀏覽器的警告:

提示,連接不是私密連接,其實就是瀏覽器識別了證書不太對勁,沒有信任。而如果此時你信任瀏覽器,則可以正常訪問。因此,當你信任證書后,在中間人面前,又是一覽無余了。
因此,一般去申請ca證書的時候,選擇正規的CA機構進行證書申請。
浙公網安備 33010602011771號