Web技術(四):TLS 握手過程與性能優化(TLS 1.2與TLS 1.3對比)


前篇博文:TLS 加密原理中介紹了TLS 如何保證通信的機密性、完整性和真實性,如何完成共享密鑰的協商交換,如何確認通信對端的真實性等問題。但面對中間人攻擊時,仍存在“無法確認用於驗證簽名的公鑰是否屬於真正的通信對端?”的問題,不過也提出瞭解決思路,引入可信的第三方對公鑰進行簽名(經可信第三方簽名認證的公鑰可以稱爲證書),證書是如何解決公鑰真實性的問題的呢?且看下文分解。

二、TLS 握手協議

2.1 證書與 PKI

前文介紹的ECDHE(Elliptic-Curve Diffie–Hellman Ephemeral)密鑰協商方案可以實現認證加密算法(比如AES-GCM)共享密鑰的交換,但密鑰協商過程容易遇到中間人攻擊問題。通過引入數字簽名(比如ECDSA / RSA)可以確認通信對端的身份,但要正確使用數字簽名,前提就是用於驗證簽名的公鑰必須屬於真正的通信對端,該如何確認自己得到的公鑰是真實合法的呢?

很容易想到的一個思路是引入可信第三方背書,就像買家與賣家之間引入支付寶類似,將要傳遞的公鑰經由可信第三方簽名(經過可信第三方簽名的公鑰可以稱爲證書或公鑰證書),只要我們能使用可信第三方公鑰驗證公鑰證書,就可以確認公鑰證書內的公鑰是合法的。我們又如何傳遞可信第三方公鑰呢?由於可信第三方屬於中心化組織,全球需要的可信第三方數量很有限,因此可以將可信第三方的公鑰集成到操作系統或瀏覽器中,不需要再額外傳遞。

但爲了防止攻擊者也申請一個公鑰證書僞裝通信對端,公鑰證書內除了包含訂閱人(申請公鑰證書的一方)的公鑰,還應包含訂閱人的身份信息(比如域名Host 信息),當然也應該包含可信第三方(也即證書頒發機構Certificate Authority)的數字簽名信息。可以說,公鑰證書或數字證書是一個主要包含訂閱人公鑰、訂閱人身份信息、證書頒發者數字簽名等相關信息的數字文件,也就是一個讓我們可以交換、存儲和使用通信對端公鑰的殼
公鑰證書籤名過程
公鑰證書或數字證書是由認證機構(CA: Certificate Authority)頒發的,使用者需要對證書進行驗證,如果證書的格式千差萬別那就不方便了。於是,人們制定了證書的標準規範,其中使用最廣泛的是由 ITU(International Telecommunication Union)定義,經PKIX(Public-Key Infrastructure standards for X.509)工作組改造過的X.509規範(RFC5280)。

符合X.509標準的公鑰證書不止包含訂閱人公鑰、訂閱人身份信息、證書頒發者數字簽名信息,還包括更多別的字段信息,我們以 https 證書爲例,使用Microsoft Chromium Edge瀏覽器 --> 更多工具 --> 開發人員工具 --> 安全,可以查看到證書狀態與安全連接設置,點擊“查看證書”可以看到證書的基本/常規信息:
查看HTTPS證書信息
我們查看證書的詳細信息,看標準的公鑰證書一般包含哪些字段:
HTTPS證書詳細信息示例
前面偏黃色的字段是版本V1 支持的基本字段,後面的屬於擴展字段,下面給出幾個主要字段的作用描述:

字段 描述
序列號 每個CA用來唯一標識其所簽發的證書,需要是無法被預測的而且至少包括20位
簽名算法
簽名哈希算法
指明證書籤名所用的算法,需要放到證書裏面,這樣才能被證書籤名保護
頒發者 包括了證書頒發者的身份信息,比如認證機構名稱、域名和所在地等信息
有效期 包括開始日期和結束日期,在這段時間內證書是有效的
使用者 包含證書申請者的身份信息,包括申請者域名、組織名稱、組織所在地等信息
公鑰
公鑰參數
包含了證書使用者的公鑰、使用的簽名算法,可選參數等信息,使用ECC比RSA有更短的公鑰也即更小的通信量

僅制定證書的規範還不足以支持公鑰的實際運用,我們還需要很多其它的規範,例如應該由誰來頒發可信的證書、如何頒發、私鑰泄露時應該如何作廢證書?到這一步,我們就已經踏入了社會學的領域,需要讓公鑰以及數字簽名技術稱爲一種社會性的基礎設施,即公鑰基礎設施(Public-Key Infrastructure),簡稱PKI。可以說,PKI 是爲了能夠更有效的運用公鑰而制定的一系列規範的總稱。PKI 主要由證書訂閱人(申請並提供證書的服務端)、證書登記註冊機構(RA: Registration Authority)、證書認證頒發機構(CA: Certification Authority)、證書使用者(請求驗證證書的客戶端)等部分構成,證書的申請與使用過程如下:
PKI證書生命週期

PKI 構成要素 功能描述
訂閱人 向註冊登記機構申請證書,根據需要申請作廢已註冊的公鑰
註冊登記機構RA 主要完成一些證書籤發的相關管理工作,比如對用戶進行必要的身份驗證(域名驗證、組織驗證、擴展驗證等)、找CA簽發證書等
認證頒發機構CA 會在確認申請用戶的身份之後簽發證書,同時CA會在線提供其所簽發證書的最新吊銷信息,方便客戶端驗證證書的有效性
使用證書的客戶端 向服務端請求證書,使用本地(比如操作系統或瀏覽器中)保存的CA公鑰驗證來自服務端的證書籤名,檢測證書的吊銷狀態等有效性信息

當證書申請者出現私鑰泄露或者不再使用證書等情況時,就需要將證書作廢。要作廢數字證書需要符合相應的標準或流程,目前主要有兩種證書吊銷標準:

  • CRL(Certificate Revocation List):證書吊銷列表CRL是一組未過期、但是卻已經被吊銷的證書序列號列表,CA維護了一個或多個這樣的列表,每一張證書都需要在CRL分發點擴展字段中包含對應的CRL地址。CRL最大的問題在於它越來越大,實時查詢起來會非常慢;
  • OCSP(Online Certificate Status Protocol):在線證書狀態協議OCSP允許驗證證書的客戶端獲得一張證書的吊銷信息,OCSP服務器的地址包含在證書的授權信息訪問擴展字段中。OCSP支持實時查詢並且解決了CRL最大的缺點,證書吊銷檢查更快速可靠,但也帶來了一些新的問題,這些問題將在網絡攻防中不斷解決。

有了用於管理傳遞公鑰的 PKI,也就解決了前一章提到的數字簽名技術無法確認通信對端真實有效性的問題。網絡攻防一直都存在,自然也少不了針對證書的攻擊,比如攻擊者可以在公鑰註冊認證前替換待認證的公鑰,證書申請者可以在向CA認證機構提交公鑰時,使用CA公鑰加密後再發送給認證機構,同時認證機構也可以再次與申請者確認收到的公鑰是否正確。還包括對認證機構本身的攻擊,比如竊取認證機構的私鑰就可以僞造證書,這主要就靠認證機構如何妥善保管升級自己的私鑰了,對於已經泄露的私鑰,及時對相關證書進行吊銷處理,儘快減小損失。

2.2 TLS 1.2 握手過程

前面已經介紹了TLS 安全傳輸的所有技術,包括信息認證加密、共享密鑰協商、通信雙方身份認證等技術方案,接下來簡單介紹TLS 協議的工作原理。前篇博文TLS 加密原理中已經介紹了,TLS 協議是由TLS 記錄協議和TLS 握手協議這兩層協議疊加而成的,位於底層的TLS 記錄協議負責進行信息傳輸和認證加密,位於上層的TLS 握手協議則負責除加密以外的其它各種操作,比如密鑰協商交換、身份認證等。TLS 記錄協議的報文結構與工作原理已經在前篇博文中簡單介紹過了,這裏重點介紹TLS 握手協議。
TLS協議層次結構
TLS 握手協議可以分爲四個子協議:

  • 握手協議:負責在客戶端和服務器之間協商決定密碼算法和共享密鑰,包括基於證書的認證操作;
  • 密碼規格變更協議:負責向通信對象傳達變更密碼方式的信號,在TLS 1.3版本中不再需要該協議;
  • 警告協議:負責在發生錯誤時將錯誤傳達給對方;
  • 應用數據協議:將TLS 上面承載的應用數據傳達給通信對象的協議。

TLS 握手過程也可以看到這四個子協議發揮作用的地方,警告協議只在發生錯誤異常時才發揮作用,所以正常的握手過程只看得到握手協議、密碼規格變更協議、應用數據協議這三部分。TLS 1.3 版本進一步優化了整個握手過程,因爲廢棄了很多不安全的加密算法,僅支持5種安全高效的加密組件(TLS 1.2支持多達37個加密組件),精簡的加密組合可以不再需要密碼規格變更協議,減少了通信雙方握手階段的往返次數。

由於TLS 1.2 協議仍是目前主流,這裏先介紹TLS 1.2 的握手過程(TLS 1.3的優化改進比較大,將在下文介紹),圖示如下:
TLS 1.2 完整握手過程
TLS 握手過程主要包括協商雙方使用的密碼套件、協商交換共享密鑰、通信對端身份認證、協商變更密碼方式等過程,從安全性角度考慮,完整的握手過程應該包含客戶端與服務器端通信雙方的身份認證,我們在訪問網上銀行之類對身份驗證比較敏感的網站時,常需要安裝數字證書,這個數字證書就是用於進行客戶端身份認證的。

但申請使用數字證書是要收費的,數字證書的費用通常由服務器端支付(比如我們使用網上銀行在個人電腦上安裝的數字證書是由銀行幫我們申請並支付費用的),很多時候我們訪問網站主要是爲了獲取信息,並不需要對服務器資源進行敏感重要的修改,服務器並不需要對客戶端進行身份認證(可以由上層HTTP協議使用基於賬號密碼等只有用戶知道的信息進行用戶認證),因此可以省去服務器向客戶端請求身份認證的過程,也就是上圖右半部分所示的握手過程。

從安全性與完整性角度考慮,下面主要按照上圖左半部分所示的完整握手過程進行介紹,從上圖可以看出TLS 1.2 完整的握手過程(從發送第一個握手報文到發送第一個用戶數據報文)需要在客戶端與服務器之間完成兩次往返通信,也即 2-RTT(Round Trip Time)。把客戶端與服務器之間完整握手過程中每個握手報文的作用及傳遞的主要參數字段展開,如下圖所示(可以參考博文:The Illustrated TLS 1.2 Connection):
TLS 1.2完整握手過程
上圖中的握手過程主要完成了下面幾個任務:

客戶端報文名 任務描述 服務器端報文名
ClientHello
-
通信雙方協商確定使用的密碼套件與壓縮方式 -
ServerHello
-
-
Certificate
CertificateVerify
雙方通過公鑰證書交換公鑰,並通過數字簽名驗證對方的身份 Certificate
CertificateRequest
-
-
-
ClientKeyExchange
通信雙方協商預備共享密鑰(後續還需要通過計算生成主共享密鑰),有兩種方案:
一、使用(EC)DHE密鑰協商算法,雙方交換域參數和公共參數,再各自計算出預備共享密鑰(推薦,TLS 1.3 支持的唯一密鑰協商方案);
二、使用RSA加密法,客戶端生成預備共享密鑰,使用服務器公鑰加密後發送給服務器(不推薦,因不支持前向保密,TLS 1.3 已棄用該方案);
ServerKeyExchange
-
ChangeCipherSpec
-
通信雙方約定後續對消息的加密方式將變更爲,使用已協商出的共享密鑰進行認證加密通信 -
ChangeCipherSpec
Finished
-
表示握手過程結束,雙方對整個握手過程的所有報文消息進行完整性驗證,防止攻擊者在中途僞造握手報文 -
Finished

TLS 1.2 握手過程ClientHello與ServerHello報文中,雙方交換的隨機數有什麼用呢?ClientKeyExchange與ServerKeyExchange報文中協商出的共享密鑰爲何叫預備共享密鑰呢?主要是因爲使用不同的密鑰交換方法,得到的共享密鑰長度可能不同,所以需要基於預備共享密鑰和客戶端/服務器的隨機數再計算出主共享密鑰,用於後續消息認證加密的密鑰。

還記得前篇博文介紹的僞隨機函數PRF(Pseudo Random Function)嗎?TLS 1.2 握手過程協商出的預備共享密鑰作爲PRF的secret參數,雙方交換的隨機數作爲PRF的seed參數,經PRF計算得出後續認證加密所用的主共享密鑰master_secret:

master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)

完整的握手協議比較複雜,需要很多握手消息和兩次網絡往返(2-RTT)才能開始發送應用數據,如果之前客戶端與服務器之間已經完成握手過程,因爲網絡問題或暫時不用而斷開了連接,再次恢復TLS 會話時能否利用之前的握手信息省去一些過程,迅速恢復TLS 會話呢?

還記得前面TLS 1.2握手過程ClientHello與ServerHello報文中的會話ID字段信息嗎?最初的會話恢復機制就是利用會話ID字段信息(由服務器在首次收到ClientHello握手報文後創建,並通過ServerHello握手報文傳遞給客戶端)實現會話快速恢復的,客戶端和服務器在TLS 連接斷開後都會將會話的安全參數保存一段時間。如果客戶端想快速恢復會話,將對應的會話ID 通過ClientHello握手報文發送給服務器,服務器如果願意恢復會話,就將相同的會話ID放入ServerHello消息返回,接着使用之前協商的主共享密鑰生成一套新的共享密鑰(爲了前向保密,儘量做到每次會話使用不同的密鑰),通信雙方再通過ChangeCipherSpec報文約定變更到新的加密方式,最後通過Finished報文完成簡短握手過程的完整性校驗,後面就可以進行應用數據認證加密通信了。
TLS 1.2 會話快速恢復簡短握手過程
TLS 1.2 會話恢復的簡短握手過程從發送第一個報文ClientHello到發送應用數據,只需要一次網絡往返 1-RTT(上圖中的客戶端發送5/6報文後可以立即發送應用數據,故在發送應用數據前僅算一次網絡往返),顯然比前面介紹的完整握手過程高效得多(省去了身份認證過程和密鑰協商過程)。但使用會話ID 快速恢復會話也有弊端,比如:

  • 在分佈式服務器中,多機之間往往沒有同步 Session ID 信息,如果客戶端兩次請求沒有落在同一臺服務器上就無法找到匹配的信息;
  • 服務器端存儲 Session ID 對應的信息不好控制失效時間,太短起不到作用,太長又佔用服務端大量資源。

爲了解決使用Session ID的問題,又引入了Session Ticket 作爲新的會話恢復方案。Session Ticket 是用只有服務器端知道的安全密鑰加密過的會話信息(包含恢復會話所需的所有信息),由服務器端在完成完整的握手過程後生成New Session Ticket 併發送給客戶端保存。如果客戶端想快速恢復會話,可以將對應的Session Ticket 通過 ClientHello 報文發送給服務器,只要服務器能驗證Session Ticket 的完整性,併成功解密其內容,就可以使用其中的信息快速恢復會話。

Session Ticket 與 Session ID 會話恢復方案的主要區別就是,Session Ticket 將會話恢復所需的信息保存在客戶端(與HTTP Cookie的原理類似),Session ID 將會話恢復所需的信息保存在服務器端,當採用分佈式服務器集羣時,顯然Session Ticket 是更合適的會話恢復方案(TLS 1.3 僅支持類似Session Ticket 的會話恢復方案)。

2.3 TLS 1.3 握手過程

TLS 1.3 廢棄了RSA密鑰交換方案(因爲RSA不具有前向保密性),僅支持(EC)DHE密鑰協商方案,簡化的密鑰協商過程能帶來TLS 握手過程的簡化嗎?

RSA密鑰交換方案需要客戶端先拿到服務器的公鑰證書,使用服務器公鑰來加密要發送的預備共享密鑰,所以RSA密鑰交換需要在第二個網絡往返中交換共享密鑰。DHE密鑰協商方案則沒有這個限制,雖然理論上客戶端也需要先拿到服務器提供的域參數(比如前篇博文介紹DHE中的G、P兩個參數,或者ECDHE中的橢圓曲線類型)才能計算出自己的密鑰協商參數(比如DHE中的Gc mod P),但這並非必要條件。客戶端可以像發送支持的加密套件列表那樣,向服務器發送支持的域參數組合列表(比如橢圓曲線類型列表)及其對應的密鑰協商參數,服務器只需要從列表中選擇一組確定爲雙方使用的域參數即可,這樣就可以在第一個網絡往返中協商共享密鑰了。

TLS 1.3 可以在第一個網絡往返中完成共享密鑰協商和身份認證,前面介紹TLS 1.2完整握手過程時也談到,TLS 1.3 精簡的加密組合可以不再需要密碼規格變更協議,在完成共享密鑰協商和身份認證後可以直接切換到應用數據協議,所以TLS 1.3 完整握手過程只需要一個網絡往返(1-RTT)便可完成,很顯然比TLS 1.2 完整握手所需的2-RTT 要更加高效。TLS 1.3 完整握手過程圖示如下:
TLS 1.3完整握手過程
從TLS 1.3 的握手過程可以看出,在第一個網絡往返就藉助key_share 擴展字段完成了密鑰協商,後續的身份認證報文均被協商出的handshake_key 加密處理,整個握手過程的明文信息減少了。爲便於理解key_share 擴展字段是如何交換(EC)DHE密鑰協商方案的有限域參數組(比如橢圓曲線類型)和對應的密鑰協商參數的,下面給出key_share 字段的數據結構(參考自:TLS 1.3 Handshake Protocol):

struct {
          NamedGroup group;						//有限域參數組或橢圓曲線類型
          opaque key_exchange<1..2^16-1>;		// 密鑰協商參數
      } KeyShareEntry;

// 下面每一個名稱對應一個確定的橢圓曲線或一組確定的有限域參數,按優先級從高到低排列,由ClientHello報文的Extension - Supported Groups擴展字段記錄這些用於密鑰交換的命名組
enum {

          /* Elliptic Curve Groups (ECDHE) */
          secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019),
          x25519(0x001D), x448(0x001E),

          /* Finite Field Groups (DHE) */
          ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096(0x0102),
          ffdhe6144(0x0103), ffdhe8192(0x0104),

          /* Reserved Code Points */
          ffdhe_private_use(0x01FC..0x01FF),
          ecdhe_private_use(0xFE00..0xFEFF),
          (0xFFFF)
      } NamedGroup;

由於取消了密碼規格變更協議,服務器在發送完CertificateVerify握手報文後可以直接發送Finished握手結束報文,服務器握手結束後在不需要對客戶端進行身份認證時(也即僅對服務器端進行身份認證的情形)可以直接發送應用數據。客戶端完成服務器身份認證後向服務器發送自己的身份認證報文,客戶端發送完Finished握手結束報文後可以直接向服務器發送應用數據(已對服務器進行過身份認證)。從客戶端發送ClientHello握手報文到發送應用數據,中間只經過一次網絡往返(1-RTT)

值得一提的是,TLS 1.3 完整握手過程允許服務器對客戶端進行後握手身份認證(Post-Handshake Client Authentication),也即初始握手時先不對客戶端進行身份認證,當客戶端請求訪問某些敏感資源時,纔要求客戶端進行身份認證。

TLS 1.3握手報文ClientHello與ServeHello在進行密鑰協商時並沒有進行數字簽名,通信雙方的身份認證主要靠後續的Certificate與CertificateVerify報文保證,因爲CertificateVerify報文是對之前的握手消息(自然包括密鑰協商消息)進行簽名,身份認證放到後面也不會影響整個握手過程的安全性。把客戶端與服務器之間完整握手過程中每個握手報文的作用及傳遞的主要參數字段展開,如下圖所示(可以參考博文:The New Illustrated TLS 1.3 Connection):
TLS 1.3完整握手過程
上圖中的握手過程主要完成了下面幾個任務:

客戶端報文名 任務描述 服務器端報文名
ClientHello:Cipher_Suites
ClientHello:Signature_Algorithms
-
-
通信雙方協商確定使用的密碼套件和數字簽名算法 -
-
ServerHello:Cipher_Suites
ServerHello:Signature_Algorithms
ClientHello: Key_Share
ClientHello: Supported_Groups
-
-
通信雙方使用(EC)DHE密鑰協商方案,交換橢圓曲線類型和密鑰協商參數,再各自計算出預備共享密鑰 -
-
ServerHello: Key_Share
ServerHello: Supported_Groups
-
-
Certificate
CertificateVerify
雙方通過公鑰證書交換公鑰,並通過對握手消息的數字簽名驗證對方的身份 Certificate
CertificateRequest
-
-
-
Finished
表示握手過程結束,雙方對整個握手過程的所有報文消息進行完整性驗證,防止攻擊者在中途篡改或僞造握手報文 Finished
-

TLS 1.3 完整握手過程在ClientHello與ServerHello報文中交換了各自的隨機數,也協商出了預備共享密鑰,使用預備共享密鑰生成主共享密鑰的方式跟前面介紹的TLS 1.2差不多,但升級了僞隨機函數PRF。

TLS 1.3 使用HKDF(HMAC based Key Derivation Function)生成主共享密鑰(TLS 1.2使用的是PRF僞隨機函數),相比PRF可以輸出安全性更強的新密鑰。HKDF包括extract_then_expand的兩階段過程,extract過程增加密鑰材料的隨機性,在TLS 1.2中使用的密鑰派生函數PRF實際上只實現了HKDF的expand部分,並沒有經過extract,而直接假設密鑰材料的隨機性已經符合要求。HKDF的算法比較複雜,這裏就不展開介紹了,有興趣瞭解的可以參考博文:TLS協議中PRF和TLS1.3中的HKDF

TLS 1.3 的完整握手過程相比TLS 1.2 已經有了不小的優化,從2-RTT 優化到了1-RTT。如果客戶端與服務器之間已完成過完整的握手過程,中間因爲某些原因斷開了,利用會話緩存快速恢復會話,還能比TLS 1.2 帶來更簡短快捷的握手過程嗎?

得益於TLS 1.3 取消了密碼規格變更協議,會話緩存快速恢復的簡短握手過程應該是可以比TLS 1.2 更優的,TLS 1.2 會話恢復簡短握手只需要一個網絡往返 1-RTT,TLS 1.3 要做到更簡短,是可以達到 0-RTT 嗎?由於通信雙方之前已經完成密鑰協商與身份認證,會話緩存中是有雙方的共享密鑰的,TLS 1.3 做到會話恢復 0-RTT 的簡短握手也是完全可以的,握手過程如下:
TLS 1.3會話快速恢復簡短握手過程
TLS 1.3 採用了新的會話緩存恢復方案 — PSK (pre_shared_key)握手,該方案相當於TLS 1.2 Session Ticket 會話恢復方案的升級版。還記得TLS 1.3 完整握手過程ClientHello報文中出現的兩個擴展字段psk_key_exchange_modes和pre_shared_key嗎?PSK會話緩存恢復方案正需要藉助這兩個字段:

字段名 作用
psk_key_exchange_modes 從PSK建立主密鑰的模式有兩種,該字段可能的取值也有兩種:
1. psk_ke:僅使用PSK建立主密鑰,Server 不提供key_share 值(0-RTT);
2. psk_dhe_ke:使用PSK 和 (EC)DHE 建立主密鑰,Client 和 Server 必須提供key_share 值(1-RTT)。
pre_shared_key (PSK) 預共享密鑰標識,也即"New Session Ticket + Binders",New Session Ticket 包含PSK初始值、名稱、有效期等信息,Binders 包含PSK與當前握手的綁定信息。
early_data 當通信雙方有預共享密鑰 PSK 時,TLS 1.3 允許在ClientHello報文的擴展字段 early data 中攜帶應用數據(攜帶數據量不超過max_early_data_size值),early_data中的應用數據使用PSK 生成的early_secret 加密。
EndOfEarlyData 如果在ClientHello報文中發送了early_data,在收到Server_Finished報文後發送EndOfEarlyData報文,表示已傳輸完了所有 0-RTT application_data 消息,並且接下來的application_data 消息使用新的密鑰application_secret 加密

TLS 1.3 完成完整握手過程後,服務器也會生成一個 New Session Ticket 併發送給客戶端保存。New Session Ticket 中包含恢復共享密鑰、有效期、隨機數nonce等信息,可以使用New Session Ticket 中的信息生成預共享密鑰PSK,過程大概如下:

struct {
          uint32 ticket_lifetime;
          uint32 ticket_age_add;
          opaque ticket_nonce<0..255>;
          opaque ticket<1..2^16-1>;
          Extension extensions<0..2^16-2>;
      } NewSessionTicket;
      
// 通過HKDF生成預共享密鑰PSK,resumption_master_secret是在完整握手過程隨主密鑰一起生成的
// ticket_nonce對於每個NewSessionTicket都是不同的,保證不同的NewSessionTicket生成不同的PSK
PSK = HKDF-Expand-Label(resumption_master_secret,
                       "resumption", ticket_nonce, Hash.length)

從上圖TLS 1.3 會話恢復簡短握手過程可以看出,發送首個報文ClientHello時就可以通過early_data 發送應用數據,因此從發送首個報文到發送應用數據之間並沒有經過網絡往返,也即0-RTT。因爲發送early_data 不依賴ServerHello消息,安全性自然更弱一些,如果攻擊者捕獲發送到服務器的 0-RTT 數據包,他們可以重播該數據包,並且服務器可能會接受該數據包爲有效數據包,甚至藉此改變服務器上的重要資源狀態,這就是 0-RTT 重放攻擊:
0-RTT重放攻擊
爲了應對 0-RTT 攻擊,一般會限制 0-RTT 會話恢復的使用範圍,比如在 0-RTT 中發送不改變服務器資源狀態的HTTP GET報文等。TLS 1.3 會話恢復簡短握手過程完成後,用於加密應用數據的密鑰是雙方再計算出來的密鑰,包含了雙方隨機數或握手報文散列值信息,保證每次會話儘可能使用一次性密鑰,同時也具備前向保密性。

三、TLS 性能優化

TLS 主要是爲了保證網絡信息安全傳輸,核心是密鑰交換、身份認證、加密解密等,我們想優化TLS 性能,可以從加解密效率、密鑰交換效率、身份認證效率、附加傳輸數據量、握手過程網絡往返次數、網絡往返時間等方面着手。

3.1 TLS 數據處理效率優化

TLS 協議最重要的數據處理就是加解密,包括對稱加解密、MAC計算、密鑰協商計算、數字簽名與驗證等。

首先,看對稱加密與MAC計算相關的算法效率對比(參考前篇博文:TLS 1.2/1.3 加密原理):
幾種密碼套件性能對比
從上圖可以看出,選擇安全高效的加解密算法,能顯著提高TLS 的整體效率。TLS 1.3 優先推薦的認證加密算法AES-GCM 支持並向計算,具有更高的加解密效率。

接下來看密鑰協商算法的效率對比:
TLS 密鑰協商算法性能對比
從上圖可以看出,橢圓曲線運算能顯著提高密鑰協商算法的效率,TLS 1.3優先推薦的ECDHE-ECDSA密鑰協商與數字簽名算法具有更高的效率,能明顯提升TLS 的整體效率。公鑰證書的簽名算法自然也包含在內,使用橢圓曲線運算的簽名算法能帶來更高的身份驗證效率。

除了選擇效率更高的加解密算法和密鑰協商-數字簽名算法,還可以在有特殊需求的設備上,使用硬件安全模塊(hardware security module),帶來更進一步的效率提升。硬件安全模塊可以在佔用更少處理器資源的情況下,實現比處理器更高的計算效率,因爲硬件安全模塊是爲加解密算法專門優化設計的處理器,自然比電腦上使用的通用處理器有更高的加解密效率。

3.2 TLS 數據傳輸效率優化

TLS 協議數據傳輸主要包括傳輸數據量、握手過程往返次數、網絡往返時間等。

TLS 握手協議身份驗證過程,需要傳輸整個數字證書信任鏈,因爲根認證機構數量有些,不可能所有的服務器都直接找根認證機構申請證書。爲了提高證書的申請與管理效率,證書的申請認證是分層級的,從根證書到申請機構可能有多箇中間層級的認證機構,這些中間層級的認證機構都需要有上一級的認證機構數字簽名纔是可信的,最終一直到根認證機構簽名。我們使用的操作系統或瀏覽器中可能只有根認證機構的公鑰,從根認證機構的證書逐層往下驗證到服務器的證書頒發機構。很顯然,證書鏈越短,進行身份認證需要傳輸的數據量越少,身份認證效率自然越高
TLS證書信任鏈
證書的吊銷檢查也是影響效率的一個關鍵環節,使用OCSP(Online Certificate Status Protocol)進行吊銷狀態實時查詢顯然比CRL(Certificate Revocation List)能帶來更高的查詢效率。爲了進一步優化證書吊銷狀態查詢時間,服務端可以在證書鏈中封裝證書頒發機構的 OCSP響應(服務器可提前查詢證書狀態,獲得OCSP響應),從而讓瀏覽器跳過在線證書狀態查詢過程,這種優化技術叫做OCSP stapling。
TLS記錄層對應用數據處理過程
TLS 記錄報文的附加數據量(比如報文標頭、初始向量/Nonce、填充/HMAC等)也是影響效率的一環,上層對應用數據的壓縮可以減小傳輸量,選用不同的密碼套件需要的附加數據量大小也有區別,下面給出幾種加密算法的傳輸開銷對比(傳輸時需要附加的數據量大小):
幾種加密算法的傳輸開銷對比
從上圖可以看出,認證加密算法AES-GCM 和 ChaCha20-Poly1305(因RC4已不再安全,這裏替換爲ChaCha20)具有更小的傳輸開銷,能爲 TLS 帶來整體的傳輸效率提升。

接下來看TLS 握手過程的性能優化,最直觀的就是網絡往返次數與單次往返時間,先看TLS 1.2與TLS 1.3 分別在首次完全握手與會話恢復簡短握手過程中需要的網絡往返次數對比:
TLS 1.2/1.3 完全握手與簡短握手的RTT次數對比
從上圖可以看出,TLS 1.3 不管是在首次完整握手過程,還是會話恢復的簡短握手過程中,都比TLS 1.2 少了一次網絡往返,自然能帶來更高的握手效率。因此,使用TLS 1.3 不僅更安全,更重要的是能帶來明顯的效率提升。

還有一個影響TLS 效率的重要因素:單次網絡往返時間,減少了網絡往返次數,自然也不能放過對單次網絡往返時間的優化。影響單次網絡往返時間的因素主要有哪些呢?主要是網絡帶寬與網絡距離兩個方面,網絡帶寬由寬帶運營商提供,購買更大帶寬的網絡服務自然能明顯提高網絡傳輸效率。

如果網絡帶寬固定,能否通過縮短網絡距離來獲得更高的傳輸效率呢?你可能會說服務器和客戶端的位置都是固定的,怎麼縮短二者之間的距離呢?客戶端訪問服務器重要的是訪問上面的資源,也就是說哪個設備上面有我們想要訪問的資源,哪個設備就可以看作服務器,雖然源服務器位置固定,但可以把相應的資源放到離客戶端更近的設備上,這就縮短了網絡訪問距離。

有一種很流行的縮短網絡訪問距離的方案CDN(Content Delivery Network)內容分發網絡,可以將用戶可能訪問的資源放到地理上分散的服務器緩存(邊緣緩存)中,用戶直接從就近的邊緣服務器中獲取資源,網絡訪問距離自然大大縮短。CDN中這些地理上分散的服務器還可以與源服務器建立長時間的連接,來降低客戶端與源服務器建立連接的成本,縮短了網絡連接距離。

TLS 握手過程如果從與遠端的源服務器握手,到與附近的CDN服務器握手,這就極大的縮短了網絡訪問距離,自然也就縮短了單次網絡往返時間,顯著提高 TLS 傳輸效率。
使用CDN與直接傳輸RTT耗時對比
從上圖可以看出,用戶與附加的CDN服務器進行數據傳輸的單次網絡往返時間明顯短得多,用戶需要訪問的資源如果附加的CDN服務器沒有,可以由該邊緣服務器向源服務器請求相應資源後給用戶響應。

從TLS 協議與下層網絡協議的交互過程着手,也可以想到性能優化的方法,我們知道網絡分層架構中每層協議支持的數據包大小不同,每一層協議都會對應用數據進行分片封裝,TLS 協議要想減少網絡傳輸的數據包總數,可以設置合適的TLS 記錄報文大小來配合下層協議,儘量讓下層協議儘可能按最大能力傳輸數據包,不至於出現很多較小數據量的網絡數據幀。通俗點說就是,儘可能讓每個網絡數據幀都接近滿載傳輸,避免出現接近空載的網絡數據幀。

更多文章:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章