文章目錄
- 簡介
- TLS
- TLS第一次握手
- 1.Client Hello
- TLS第二次握手
- 2.Server Hello
- 3.Certificate
- 4.Server Hello Done
- TLS第三次握手
- 5.Client Key Exchange
- 6.Change Cipher Spec
- 7.Encrypted Handshake Message
- TLS第四次握手
- 8.New Session Ticket
- 9.Change Cipher Spec
- 10.Encrypted Handshake Message
- 總結
簡介
我們知道http傳輸數據是明文傳輸,明文傳輸存在三個問題:
- 竊聽風險:由于是明文傳輸,到達目標之前的所有鏈路都可以看到傳輸的內容。
- 篡改風險:如果傳輸過程中間數據被修改,接收方也無法得知。
- 冒充風險:由于知道傳輸的內容,中間人可以冒充接收方。
在計算機發展的早期只是使用http傳輸簡單的數據,發展到現在絕大部分數據傳輸都是基于http協議,如果還使用明文傳輸顯然不太安全,特別是涉及賬號密碼相關的內容,https就是在http的基礎上添加了安全傳輸層,其中s代表SSL(Secure Sockets Layer)或者TLS(Transport Layer Security),SSL是早期的版本,由網景公司在1990年代早期開發。TLS是其后續版本,由互聯網工程任務組(IETF)開發,SSL有SSL1.0、SSL2.0和SSL3.0,TLS有TLS1.0、TLS1.1、TLS1.2和TLS1.3,目前主流的版本是TLS1.2和TLS1.3。下面我們來介紹TLS是怎么實現安全傳輸的。我們以目前主流的TLS1.2作為介紹對象。
TLS
我們先看下TLS的流程:
根據上圖我們可以把TLS分為以下幾步:
1.服務端生成一對非對稱加密的密鑰對,把自己的公鑰交給CA機構生成一個證書,什么是CA呢?因為非對稱加密通過公鑰加密數據,通過私鑰解密數據,服務端擁有公鑰私鑰,但是客戶端什么都不知道,所以需要將公鑰傳給客戶端,但是直接發給客戶端可能會被中間人攔截替換,TLS通過引入一個雙方可以信任的第三方即CA來解決這個問題。
- CA會將服務端的公鑰、頒發者、有效時間等信息打成一個包,然后對這些信息進行 Hash 計算,得到一個 Hash 值(也稱證書指紋)
- 然后 CA 會使用自己的私鑰將該 Hash 值加密,生成 Certificate Signature(證書簽名)
- 最后將 Certificate Signature 添加在文件證書上,形成數字證書。由于證書簽名使用CA的私鑰加密,解密自然只能用CA的公鑰。我們的客戶端(Android,Windows,iOS等)都會集成全球主流的CA的公鑰信息到操作系統中。
2.當客戶端向服務端請求數據的時候,服務端把這個證書發送給客戶端,客戶端拿到證書后可以得到服務端的公鑰、頒發者、有效時間、證書簽名和所屬的CA等信息。
- 首先客戶端會使用同樣的 Hash 算法獲取該證書的 Hash 值 H1
- 再從操作系統中尋找這個CA的公鑰,通過公鑰解密證書里的簽名數據得到Hash值H2
- 最后比較 H1 和 H2,如果值相同,則為可信賴的證書。
通過CA客戶端可以驗證服務端的身份,防止有人冒充。
3.客戶端已經拿到了可以用來加密的公鑰,正常來說現在已經可以進行加密通訊了,但是由于非對稱加密較復雜,加密耗時較久,而且加密后內容明顯變大,所以在頻繁的通訊中使用是非常不劃算的,所以這里并沒有直接用公鑰加密傳輸數據,而是引入了對稱加密,在客戶端隨機生成一個對稱加密密鑰,并使用公鑰加密后傳給服務器,由于只有服務器有私鑰,所以中間攔截也沒用,服務器接收到數據后解密拿到對稱加密密鑰,后續的通訊就使用對稱加密進行加密。(雖然對稱加密的安全性不如非對稱加密,但是由于每次連接都會生成一個隨機的密鑰,所以安全性上也是可以接受的。)
上面只是大致的流程,實際實現和上面說的還是有很大區別的,下面我們分析一次實際中TLS握手的完整過程,什么是TLS的握手呢?其實就是通訊雙方通過上面的方法協商一個共同的密鑰的過程,他的完整流程是這樣的:
上圖有多次通信過程,可以分成4次握手,下面我們通過抓包看一下實際的TLS的握手過程,首先看一下wireshark中完整的TLS握手記錄:
上圖中有多個握手過程,我把其中一個握手的完整過程標記出來了,下面我們來詳細介紹每一步的作用。
TLS第一次握手
1.Client Hello
上圖是client hello的所有內容,我們重點關注紅框中的內容:
1.Version是客戶端的TLS版本,我們看到是1.2
2.Random是客戶端生成的一個隨機數,用于生成加密密鑰,前面我們說過客戶端拿到服務端公鑰后會生成一個隨機數當作后續通訊加密的密鑰,并把這個密鑰用公鑰加密后發送給服務端,其實這個密鑰不止一個隨機數,而是三個隨機數拼成的,其一就是這里的隨機數,其二是服務端server hello時也會傳過來的一個服務端生成的隨機數,最后才是之前說的隨機數,通過三個隨機數生成最終的密鑰是為了保證隨機性和安全性。
3.Cipher Suites是客戶端支持的加密套件,我們上面說的對稱加密和非對稱加密并沒有固定的加密算法,這個有很多選擇,我們看下客戶端支持的加密套件有哪些:
這個密碼套件看起來真讓人頭暈,好一大串,但是其實它是有固定格式和規范的。基本的形式是「密鑰交換算法 + 簽名算法 + 對稱加密算法 + 摘要算法」, 一般 WITH 單詞前面有兩個單詞,第一個單詞是約定密鑰交換的算法,第二個單詞是約定證書的驗證算法。比如我們目前分析的這個TLS_RSA_WITH_AES_128_GCM_SHA256密碼套件的意思就是:
- 由于 WITH 單詞只有一個 RSA,則說明握手時密鑰交換算法和簽名算法都是使用 RSA;
- 握手后的通信使用 AES 對稱算法,密鑰長度 128 位,分組模式是 GCM;
- 摘要算法 SHA256 用于消息認證和產生隨機數;
4.support_versions是客戶端支持的所有TLS版本,前面的version是客戶端想要使用的版本,但是服務端不一定支持,所以需要把支持所有版本給到服務端,如果服務端不支持version的版本,就在support_versions選一個。
5.session_ticket是用于復用之前的TLS連接用的,這個后面會介紹。
TLS第二次握手
2.Server Hello
1.Version是服務端選擇的TLS版本
2.Random是服務端生成的一個隨機數,用于生成加密密鑰
3.Cipher Suites是服務端選擇的加密套件
3.Certificate
這一步是將服務器的證書發送給客戶端,客戶端拿到證書后會去進行驗證,并拿到公鑰。
上圖中服務器給了兩個證書,這是為什么呢?這就要說到CA的證書鏈機制了,服務端的證書并不一定是CA根證書簽發的,而可能是CA的二級證書簽發的,CA下面會有二級三級乃至多級代理,如果是二級代理簽發的證書,就要先用根證書驗證二級代理的證書,二級代理的證書沒問題,再用二級代理的證書驗證服務器的證書。
所以上圖的第一個證書是服務器證書,第二個證書是二級代理的證書,先找到二級代理所屬的CA,去驗證二級證書,驗證無誤后再用二級證書去驗證服務器證書。
4.Server Hello Done
服務端已經完成hello,為什么需要這一步呢?
在Server Hello
之后,服務器通常會發送一系列消息,包括:
Certificate
(包含服務器的證書鏈)Server Key Exchange
(如果證書不包含足夠的信息進行密鑰交換,例如使用DHE/ECDHE算法時)Certificate Request
(可選,如果服務器要求客戶端認證)...
(其他可能的擴展消息)
這些消息的數量和類型是可變的,取決于協商的加密套件、服務器配置和是否要求客戶端認證。
Server Hello Done
的唯一作用就是清晰、明確地告訴客戶端:“我已經發送完所有我這邊在握手這一階段需要發送的信息了,沒有更多這類消息了。”
TLS第三次握手
5.Client Key Exchange
將用公鑰加密的pre-master傳遞給服務端,服務端拿到直接用私鑰解密就可以拿到pre-master,加上client的random和server的radom就可以得到回話密鑰。
客戶端隨機數 + 服務端隨機數 + 預主密鑰 = 主密鑰 ==> 會話密鑰
6.Change Cipher Spec
告訴服務端開始用會話密鑰進行加密通訊了
7.Encrypted Handshake Message
把客戶端之前所有發送的數據做個摘要,再用會話密鑰(master secret)加密一下,讓服務器做個驗證,驗證加密通信是否可用和之前握手信息是否有被中途篡改過。
TLS第四次握手
8.New Session Ticket
將session_ticket發送給客戶端保存,session_ticket是用于復用之前的TLS連接用的,由于TLS的握手比較繁瑣,自然就比較耗時,所以當握手完成后服務器端將本次的會話數據進行加密(會話標識符、證書、密碼套件和主密鑰等),加密后生成一個ticket票據(只有服務器可以解密),并將票據通過NewSessionTicket子消息發送給客戶端,客戶端保存這個ticket。當連接斷開后重新連接的時候就可以在client hello中將這個ticket發送給服務端,服務器端解密校驗無誤后拿到主密鑰,將主密鑰和client hello中的random以及服務端生成的即將在server hello中傳輸的random三個數據生成一個新的密鑰,然后server hello的時候客戶端也用同樣的三個數據生成這個密鑰,這樣就協商了一個相同的密鑰,后續就用這個密鑰進行加密通訊,如此恢復上一次會話就可以省掉之后的很多步驟。
9.Change Cipher Spec
和客戶端發送的Change Cipher Spec操作相同,告訴客戶端我準備好使用會話密鑰了
10.Encrypted Handshake Message
把服務端之前所有發送的數據做個摘要,再用會話密鑰(master secret)加密一下,讓客戶端做個驗證,驗證加密通信是否可用和之前握手信息是否有被中途篡改過。
總結
到這里TLS的流程就介紹完了,我們再看看開頭說的http的三個問題是怎么解決的:
- 竊聽風險:通過會話密鑰加密數據。
- 篡改風險:通過CA對證書進行簽名,對TLS握手過程進行摘要計算。
- 冒充風險:向CA驗證證書。
雖然解決了這三個問題,但是現在的TLS還是有缺陷的,那就是不支持前向保密,因為客戶端傳遞pre-master(用于生成對稱加密密鑰的條件之一)給服務端時使用的是公鑰加密的,服務端收到后,會用私鑰解密得到隨機數。所以一旦服務端的私鑰泄漏了,過去被第三方截獲的所有 TLS 通訊密文都會被破解。
為了解決這一問題,于是就有了 DH 密鑰協商算法TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,和我們上面介紹的TLS_RSA_WITH_AES_128_GCM_SHA256區別就是使用了ECDHE的密鑰協商算法,后面我們介紹一下這個算法。
下一篇:Https之(二)TLS的DH密鑰協商算法