TLS 握手優化詳解

jopen 9年前發布 | 14K 次閱讀 TLS 網絡技術

 

隨著 HTTP/2 的逐漸普及,以及國內網絡環境越來越糟糕(運營商劫持和篡改),HTTPS 已經開始成為主流。HTTPS 在 TCP 和 HTTP 之間增加了 TLS(Transport Layer Security),保證了傳輸層安全,同時也給 Web 性能優化帶來新的挑戰。上次寫的「 使用 BoringSSL 優化 HTTPS 加密算法選擇 」一文中,我介紹了如何針對不同平臺啟用最合適的傳輸加密算法。本篇文章我打算繼續寫 HTTPS 優化 —— TLS 握手優化。

先來補充一個小知識:SSL(Secure Sockets Layer,安全套接字層)最初是由網景公司開發的協議,提供了內容加密、身份認證和數據完整性三大功能。IETF 后來在標準化 SSL 協議時,將其改名為 TLS,主要功能沒有變化。通常沒有特別說明時,SSL 和 TLS 指的是同一個協議,本文也不做嚴格區分。

TLS 握手

在傳輸應用數據之前,客戶端必須與服務端協商密鑰、加密算法等信息,服務端還要把自己的證書發給客戶端表明其身份,這些環節構成 TLS 握手過程,如下圖所示:

TLS 握手優化詳解

可以看到,假設服務端和客戶端之間單次傳輸耗時 28ms,那么客戶端需要等到 168ms 之后才能開始發送 HTTP 請求報文,這還沒把客戶端和服務端處理時間算進去。光是 TLS 握手就需要消耗兩個 RTT(Round-Trip Time,往返時間),這就是造成 HTTPS 更慢的主要原因。當然,HTTPS 要求數據加密傳輸,加解密相比 HTTP 也會帶來額外的開銷,不過對稱加密本來就很快,加上硬件性能越來越好,所以這部分開銷還好。

詳細的 TLS 握手過程這里就不介紹了,大家可以通過這篇《 大型網站的 HTTPS 實踐(一)—— HTTPS 協議和原理 》去了解。通過 Wireshark 抓包可以清楚地看到完整 TLS 握手過程所需的兩個 RTT,如下圖:

TLS 握手優化詳解

False Start

False Start 有搶跑的意思,意味著不按規則行事。TLS False Start 是指客戶端在發送 Change Cipher Spec Finished 同時發送應用數據(如 HTTP 請求),服務端在 TLS 握手完成時直接返回應用數據(如 HTTP 響應)。這樣,應用數據的發送實際上并未等到握手全部完成,故謂之搶跑。這個過程如下圖所示:

TLS 握手優化詳解

可以看到,啟用 False Start 之后,TLS 階段只需要一次 RTT 就可以開始傳輸應用數據。False Start 相當于客戶端提前發送加密后的應用數據,不需要修改 TLS 協議,目前大部分瀏覽器默認都會啟用,但也有一些前提條件:

  • 服務端必須在 Server Hello 握手中通過 NPN(Next Protocol Negotiation,下一代協議協商,Google 在 SPDY 協議中開發的 TLS 擴展,用于握手階段協商應用協議)或 ALPN(Application Layer Protocol Negotiation,應用層協議協商,NPN 的官方修訂版)表明自己支持的 HTTP 協議,例如:http/1.1、http/2;
  • 使用支持前向安全性(Forward Secrecy)的加密算法。False Start 在尚未完成握手時就發送了應用數據,Forward Secrecy 可以提高安全性;

通過 Wireshark 抓包可以清楚地看到 False Start 帶來的好處(編號為 32 的包已經捎帶發送了請求,并在 34 號包得到響應,相當于 TLS 握手只消耗了一個 RTT):

TLS 握手優化詳解

Certificate

TLS 的身份認證是通過證書信任鏈完成的,瀏覽器從站點證書開始遞歸校驗父證書,直至出現信任的根證書(根證書列表一般內置于操作系統,Firefox 自己維護)。站點證書是在 TLS 握手階段,由服務端發送的。

Certificate-Chain

配置服務端證書鏈時,有兩點需要注意:1)證書是在握手期間發送的,由于 TCP 初始擁塞窗口的存在,如果證書太長可能會產生額外的往返開銷;2)如果證書沒包含中間證書,大部分瀏覽器可以正常工作,但會暫停驗證并根據子證書指定的父 證書 URL 自己獲取中間證書。這個過程會產生額外的 DNS 解析、建立 TCP 連接等開銷,非常影響性能。

配置證書鏈的最佳實踐是只包含站點證書和中間證書,不要包含根證書,也不要漏掉中間證書。大部分證書都是「站點證書 - 中間證書 - 根證書」這樣三級,這時服務端只需要發送前兩個證書即可。但也有的證書有四級,那就需要發送站點證書外加兩個中間證書了。

通過 Wireshark 可以查看服務端發送的證書情況,如下圖。可以看到本站發送了兩個證書,共 2270 字節,被分成 2 個 TCP 段來傳輸。這已經算小的了,理想的證書鏈應該控制在 3kb 以內。

TLS 握手優化詳解

ECC Certificate

如果需要進一步減小證書大小,可以選擇 ECC(Elliptic Curve Cryptography,橢圓曲線密碼學)證書。256 位的 ECC Key 等同于 3072 位的 RSA Key,在確保安全性的同時,體積大幅減小。下面是一個對比:

對稱加密 Key 長度 RSA Key 長度 ECC Key 長度
80 1024 160
112 2048 224
128 3072 256
192 7680 384
256 15360 521

如果證書提供商支持 ECC 證書,使用以下命令生成 CSR(Certificate Signing Request,證書簽名請求)文件并提交給提供商,就可以獲得 ECC 證書:

openssl ecparam -genkey -name secp256r1 | openssl ec -out ecc.key
openssl req -new -key ecc.key -out ecc.csr

以上命令中可以選擇的算法有 secp256r1 和 secp384r1,secp521r1 已被 Chrome 和 Firefox 拋棄。

ECC 證書這么好,為什么沒有普及呢?最主要的原因是它的支持情況并不好。例如 Windows XP 不支持,導致使用 ECC 證書的網站在 Windows XP 上只有 Firefox 能訪問(Firefox 證書那一套完全自己實現,不依賴操作系統)。另外,Android 平臺也只有 Android 4+ 才支持 ECC 證書。所以,確定使用 ECC 證書前需要明確用戶系統分布情況。

Session Resumption

另外一個提高 TLS 握手效率的機制是會話復用。會話復用的原理很簡單,將第一次握手辛辛苦苦算出來的對稱密鑰存起來,后續請求中直接使用。這樣可以節省證書傳送等環節,也可以將 TLS 握手所需 RTT 減少到一個,如下圖所示:

TLS 握手優化詳解

可以看到會話復用機制生效時,雙方幾乎不怎么交換數據就協商好密鑰了,這是怎么做到的呢?

Session Identifier

Session Identifier(會話標識符),是 TLS 握手中生成的 Session ID。服務端可以將 Session ID 協商后的信息存起來,瀏覽器也可以保存 Session ID,并在后續的 ClientHello 握手中帶上它,如果服務端能找到與之匹配的信息,就可以完成一次快速握手。

Session Ticket

Session Identifier 機制有一些弊端,例如:1)負載均衡中,多機之間往往沒有同步 Session 信息,如果客戶端兩次請求沒有落在同一臺機器上就無法找到匹配的信息;2)服務端存儲 Session ID 對應的信息不好控制失效時間,太短起不到作用,太長又占用服務端大量資源。

而 Session Ticket(會話記錄單)可以解決這些問題,Session Ticket 是用只有服務端知道的安全密鑰加密過的會話信息,最終保存在瀏覽器端。瀏覽器如果在 ClientHello 時帶上了 Session Ticket,只要服務器能成功解密就可以完成快速握手。

配置 Session Ticket 策略后,通過 Wireshark 可以看到服務端發送 Ticket 的過程:

TLS 握手優化詳解

以下是 Session Resumption 機制生效時的握手情況,可以看到沒有發送證書等環節:

TLS 握手優化詳解

OCSP Stapling

出于某些原因,證書頒發者有時候需要作廢某些證書。那么證書使用者(例如瀏覽器)如何知道一個證書是否已被作廢呢?通常有兩種方 式:CRL(Certificate Revocation List,證書撤銷名單)和 OCSP(Online Certificate Status Protocol,在線證書狀態協議)。

CRL 是由證書頒發機構定期更新的一個列表,包含了所有已被作廢的證書,瀏覽器可以定期下載這個列表用于驗證證書合法性。不難想象,CRL 會隨著時間推移變得越來越大,而且實時性很難得到保證。OCSP 是一個在線查詢接口,瀏覽器可以實時查詢單個證書的合法性。在每個證書的詳細信息中,都可以找到對應頒發機構的 CRL 和 OCSP 地址。

OCSP 的問題在于,某些客戶端會在 TLS 握手階段進一步協商時,實時查詢 OCSP 接口,并在獲得結果前阻塞后續流程,這對性能影響很大。而 OCSP Stapling(OCSP 封套),是指服務端在證書鏈中包含頒發機構對證書的 OCSP 查詢結果,從而讓瀏覽器跳過自己去驗證的過程。服務端有更快的網絡,獲取 OCSP 響應更容易,也可以將 OCSP 響應緩存起來。

OCSP 響應本身是加密過的,無法偽造,所以 OCSP Stapling 技術既提高了握手效率,也不會影響安全性。啟用這項技術后,也通過 Wireshark 來驗證:

TLS 握手優化詳解

可以看到,服務端在發送完證書后,緊接著又發來了它的 OCSP 響應,從而避免了瀏覽器自己去驗證證書造成阻塞。需要注意的是,OCSP Response 只能包含一個證書的驗證結果,瀏覽器還是可能自己去驗證中間證書。另外,OCSP Response 本身會占用幾 kb 的大小。

OCSP Stapling 功能需要 Web Server 的支持,主流的 Nginx、Apache 和 H2O 都支持 —— 但同時還取決于使用的 SSL 庫 —— 例如 BoringSSL 不支持 OCSP Stapling,使用 BoringSSL + Nginx 就無法開啟 OCSP Stapling。

如何使用 Nginx 配置本文這些策略,可以參考我之前的文章: 本博客 Nginx 配置之性能篇

最后,強烈推薦 Qualys SSL Labs 的 SSL Server Test 工具,可以幫你查出 HTTPS 很多配置上的問題。本博客的測試結果見這里。

本文一部分內容來自于 Google 性能專家 Ilya Grigorik 寫的《 High Performance Browser Networking 》第四章: Transport Layer Security (TLS) 。這是一本可以免費在線閱讀,一直都在更新的性能優化好書,本博客多次推薦。本書中文翻譯由李松峰老師負責,已經出版,名為《 WEB 性能權威指南 》。

本文鏈接: https://imququ.com/post/optimize-tls-handshake.html參與評論

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!