Transport Layer Security
傳輸層安全協議
High Performance Browser Networking | O`Reilly: Transport Layer Security (TLS)
發展歷史
Defined |
Protocol |
Year |
SSL 1.0 |
n/a |
SSL 2.0 |
1995 |
SSL 3.0 |
1996 |
TLS 1.0 |
1999 |
TLS 1.1 |
2006 |
TLS 1.2 |
2008 |
TLS 1.3 |
TBD |
對於 TLS 的發展過程以及涉及的基本概念可以參考 Wiki
完整握手
基於 RSA 的完整握手
1、客戶端傳送 ClientHello 訊息,包括 最高支援的 TLS 協議版本,隨機數,加密套件,壓縮演算法。如果希望下次重用握手,可以包含 session id。如果客戶端使用 ALPN,可以包括應用層的協議列表,比如http2
2、伺服器回一個 SeverHello 訊息,包括選擇的協議版本,隨機數,選擇的加密套件和壓縮演算法。伺服器確認或者允許重用握手可能需要傳送一個 session id。選擇的協議版本應該是客戶端和服務端都支援的最高版本
3、服務端傳送 Certificate 訊息
4、伺服器傳送 ServerKeyExchange 訊息,使用RSA進行金鑰交換無需交換任何臨時引數,所以可以沒有 ServerKeyExchange 階段,
5、伺服器傳送 ServerHelloDone 訊息,表示握手協議完成
6、客戶端生成 PreMasterSecret 並用伺服器的公鑰加密,回應 ClientKeyExchange 訊息,包括 PreMasterSecret,可能包括客戶端的公鑰。
7、客戶端和服務端利用兩個隨機數和 PreMasterSecret 生成 master secret,也就是接下來使用的對稱祕鑰(Session Key)
8、客戶端傳送 ChangeCipherSpec 告訴對方接下來所有的訊息都是經過加密的
9、最後客戶端傳送加密的 Finished 訊息,並且包含 MAC。伺服器解密並且驗證 MAC,如果解密或者驗證失敗,握手失敗
10、服務端傳送 ChangeCipherSpec 告訴對方接下來所有的訊息都是經過加密的
11、服務端傳送加密的 Finished 訊息,客戶端解密並驗證
12、握手完成
基於 RSA 驗證客戶端的完整握手
有時候客戶端需要驗證,這就導致比基本的TLS握手多了兩個步驟。客戶端在 ServerHelloDone 訊息之後傳送 Certificate 訊息,攜帶自己的證書。並且傳送 CertificateVerify 訊息,攜帶經過自己私鑰加密的簽名。伺服器收到證書和簽名之後用客戶端的公鑰做驗證。
基於 Diffie-Hellman 的完整握手
迪菲-赫爾曼金鑰交換
這裡其實主要是多了一個步驟,ServerKeyExchange 交換 DH parameter,使用 Diffie-Hellman parameters 生成 PreMasterSecret
簡易握手
Session ID
一般現在Web伺服器的架構是Nginx+OpenSSL(假設是),Nginx只支援單機多程式間共享的Session Cache,所以為了可靠性一般需要有全域性的分散式Session Cache,這樣就能保證在多臺Web伺服器之間共享使用Session ID。
Session Cache 的方案需要在伺服器做快取,會導致服務端需要較大的記憶體。
Session Ticket
Session Ticket 是不需要消耗伺服器的記憶體的,但必須保證 Nginx 叢集使用相同的 Session Ticket 加解密演算法,不然就會導致 Session Ticket 在不同的 Nginx 機器上解密錯誤而不能重用。
Session Ticket 也是現在主流使用的快速握手方案,但是在應用重啟就會導致 Session Ticket 丟失的問題,就必須要重新走完整握手的方案。對這一問題騰訊提出了一個解決方案,參考:騰訊HTTPS效能優化實踐。
TLS 協議
參考 Wiki: TLS Record
Optimizing the TLS record size:Optimizing TLS Record Size & Buffering Latency
加密套件
幾種常見的加密套件:
Kx 為 RSA 時候,Au 也必須為 RSA,且可以省略
KX 金鑰交換演算法
RSA:由client生成 premaster secrete,用 server 的公鑰加密後在 ClientKeyExchange 包中傳給 server,server再用自己的私鑰解密。RSA祕鑰的長度,至少應大於2048位才是安全的,較長的祕鑰使得RSA解密一個256位的 premaster secrete 需要2ms左右,比較消耗服務端CPU資源。
ECDHE (Elliptic Curve Diffie–Hellman Exchange) = ECC + DH + E,是在DH演算法的基礎上,加入了橢圓曲線演算法,使得所需祕鑰的長度變短,最後的E表示每次動態生成引數和key,其中引數使用了證書中公鑰對應的私鑰進行了簽名。
因為使用了RSA 2048位的私鑰進行簽名,引數簽名後長度變成了256位元組。如果使用金鑰為256位的ECDSA證書,則只需32個位元組。
client 使用動態引數、自己的臨時私鑰和server的臨時公鑰來生成一個premaster secret。
server 使用動態引數、自己的臨時私鑰和client的臨時公鑰(在ClientKeyExchange包中傳出)生成相同的premaster secret。
ECDHE 演算法有更短的金鑰,能更快地得到對稱加密的金鑰,相比RSA消耗更少的服務端CPU資源。而且搭配ECDSA證書會有更好的效果。
Au 簽名認證演算法
待續~~~
Enc 對稱加密演算法
互動應用層資料時使用的對稱加密演算法
MAC 檢驗演算法
Message authentication code 互動應用層資料時使用的Hash演算法,檢驗資料的完整性
MD5 以及 SHA-1 已被攻破
TLS False Start
TLS False Start是Google提出來的優化方法,其做法是:在TLS協商階段,客戶端傳送 ChangeCipherSpec 和 Finished 後,立即傳送加密的應用層資料,而無需等待伺服器端的確認。
客戶端在傳送 ChangeCipherSpec 和 Finished 後,並沒有等待伺服器端的確認就立即傳送了加密應用資料。這樣就省去了一個RT。