SSL/TLS 握手優化詳解

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

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

TLS 握手git

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

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

詳細的 TLS 握手過程這裏就不介紹了,你們能夠經過這篇《大型網站的 HTTPS 實踐(1):HTTPS 協議和原理》去了解。經過 Wireshark 抓包能夠清楚地看到完整 TLS 握手過程所需的兩個 RTT,以下圖:瀏覽器

False Start緩存

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

能夠看到,啓用 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.一、http/2;
  • 使用支持前向安全性(Forward Secrecy)的加密算法。False Start 在還沒有完成握手時就發送了應用數據,Forward Secrecy 能夠提升安全性;

經過 Wireshark 抓包能夠清楚地看到 False Start 帶來的好處(編號爲 32 的包已經捎帶發送了請求,並在 34 號包獲得響應,至關於 TLS 握手只消耗了一個 RTT):服務器

Certificate

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

Certificate-Chain

配置服務端證書鏈時,有兩點須要注意:1)證書是在握手期間發送的,因爲 TCP 初始擁塞窗口的存在,若是證書太長可能會產生額外的往返開銷;2)若是證書沒包含中間證書,大部分瀏覽器能夠正常工做,但會暫停驗證並根據子證書指定的父證書 URL 本身獲取中間證書。這個過程會產生額外的 DNS 解析、創建 TCP 鏈接等開銷,很是影響性能。

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

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

ECC Certificate

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

若是證書提供商支持 ECC 證書,使用如下命令生成 CSR(Certificate Signing Request,證書籤名請求)文件並提交給提供商,就能夠得到 ECC 證書:

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

ECC 證書這麼好,爲何沒有普及呢?最主要的緣由是它的支持狀況並很差。例如 Windows XP 不支持,致使使用 ECC 證書的網站在 Windows XP 上只有 Firefox 能訪問(Firefox 證書那一套徹底本身實現,不依賴操做系統)。另外,Android 平臺也只有 Android 4+ 才支持 ECC 證書。因此,肯定使用 ECC 證書前須要明確用戶系統分佈狀況。

Session Resumption

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

能夠看到會話複用機制生效時,雙方几乎不怎麼交換數據就協商好密鑰了,這是怎麼作到的呢?

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 的過程:

如下是 Session Resumption 機制生效時的握手狀況,能夠看到沒有發送證書等環節:

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 來驗證:

能夠看到,服務端在發送完證書後,緊接着又發來了它的 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 性能權威指南》。

相關文章
相關標籤/搜索