真正“搞”懂HTTPS協議19之HTTPS優化

  這是本系列的最後一篇了,其實本篇的內容也跟前兩篇TLS的握手和優化有關係。其實HTTPS的核心就是TLS的明文握手連接,前兩篇我們花了很大的篇幅來聊這些,另外一個就是在TLS握手完成後的密聞傳輸部分了。

  由於目前流行的 AES、ChaCha20 性能都很好,還有硬件優化,報文傳輸的性能損耗可以說是非常地小,小到幾乎可以忽略不計了。但是,HTTPS在建立連接的時候,還是要比HTTP慢。想必大家也能猜到爲什麼HTTPS的連接要比HTTP慢了,嗯……就是因爲TLS握手所產生的消耗。但是除了TLS握手的消耗外,其實還有一些隱形的損耗,比如:

  • 產生用於密鑰交換的臨時公私鑰對(ECDHE);
  • 驗證證書時訪問 CA 獲取 CRL 或者 OCSP;
  • 非對稱加密解密處理“Pre-Master”。

  在最差的情況下,也就是不做任何的優化措施,HTTPS 建立連接可能會比 HTTP 慢上幾百毫秒甚至幾秒,這其中既有網絡耗時,也有計算耗時,就會讓人產生“打開一個 HTTPS 網站好慢啊”的感覺。

  不過剛纔說的情況早就是“過去時”了,現在已經有了很多行之有效的 HTTPS 優化手段,運用得好可以把連接的額外耗時降低到幾十毫秒甚至是“零”。

一、硬件優化

  首先是硬件的優化,說白了就是花錢。由於HTTPS連接是計算密集型,所以你可以花錢買更快的CPU,最好還可以內建AES優化,這樣既可以加快握手的速度,還可以加快傳輸的速度。

  其次,你可以選擇“SSL 加速卡”,加解密時調用它的 API,讓專門的硬件來做非對稱加解密,分擔 CPU 的計算壓力。

  不過“SSL 加速卡”也有一些缺點,比如升級慢、支持算法有限,不能靈活定製解決方案等。

  所以,就出現了第三種硬件加速方式:“SSL 加速服務器”,用專門的服務器集羣來徹底“卸載”TLS 握手時的加密解密計算,性能自然要比單純的“加速卡”要強大的多。

二、軟件優化

  軟件優化主要分爲兩部分:一個是軟件升級,一個是協議優化。我們先來說軟件升級。

  軟件升級實施起來比較簡單,就是把現在正在使用的軟件儘量升級到最新版本,比如把 Linux 內核由 2.x 升級到 4.x,把 Nginx 由 1.6 升級到 1.16,把 OpenSSL 由 1.0.1 升級到 1.1.0/1.1.1。

  由於這些軟件在更新版本的時候都會做性能優化、修復錯誤,只要運維能夠主動配合,這種軟件優化是最容易做的,也是最容易達成優化效果的。

  但對於很多大中型公司來說,硬件升級或軟件升級都是個棘手的問題,有成千上萬臺各種型號的機器遍佈各個機房,逐一升級不僅需要大量人手,而且有較高的風險,可能會影響正常的線上服務。所以,在軟硬件升級都不可行的情況下,我們最常用的優化方式就是在現有的環境下挖掘協議自身的潛力。

三、協議優化

  如果有可能,應當儘量採用 TLS1.3,它大幅度簡化了握手的過程,完全握手只要 1-RTT,而且更加安全。

  如果暫時不能升級到 1.3,只能用 1.2,那麼握手時使用的密鑰交換協議應當儘量選用橢圓曲線的 ECDHE 算法。它不僅運算速度快,安全性高,還支持“False Start”,能夠把握手的消息往返由 2-RTT 減少到 1-RTT,達到與 TLS1.3 類似的效果。

  另外,橢圓曲線也要選擇高性能的曲線,最好是 x25519,次優選擇是 P-256。對稱加密算法方面,也可以選用“AES_128_GCM”,它能比“AES_256_GCM”略快一點點。

四、證書優化

  除了密鑰交換,另外一個耗時的東東就是證書驗證了。服務器需要把自己的證書鏈全發給客戶端,然後客戶端接收後再逐一驗證。

  這裏就有兩個優化點,一個是證書傳輸,一個是證書驗證

  服務器的證書可以選擇橢圓曲線(ECDSA)證書而不是 RSA 證書,因爲 224 位的 ECC 相當於 2048 位的 RSA,所以橢圓曲線證書的“個頭”要比 RSA 小很多,即能夠節約帶寬也能減少客戶端的運算量,可謂“一舉兩得”。

  客戶端的證書驗證其實是個很複雜的操作,除了要公鑰解密驗證多個證書籤名外,因爲證書還有可能會被撤銷失效,客戶端有時還會再去訪問 CA,下載 CRL 或者 OCSP 數據,這又會產生 DNS 查詢、建立連接、收發數據等一系列網絡通信,增加好幾個 RTT。

  CRL(Certificate revocation list,證書吊銷列表)由 CA 定期發佈,裏面是所有被撤銷信任的證書序號,查詢這個列表就可以知道證書是否有效。但 CRL 因爲是“定期”發佈,就有“時間窗口”的安全隱患,而且隨着吊銷證書的增多,列表會越來越大,一個 CRL 經常會上 MB。想象一下,每次需要預先下載幾 M 的“無用數據”才能連接網站,實用性實在是太低了。所以,現在 CRL 基本上不用了,取而代之的是 OCSP(在線證書狀態協議,Online Certificate Status Protocol),向 CA 發送查詢請求,讓 CA 返回證書的有效狀態。但 OCSP 也要多出一次網絡請求的消耗,而且還依賴於 CA 服務器,如果 CA 服務器很忙,那響應延遲也是等不起的。於是又出來了一個“補丁”,叫“OCSP Stapling”(OCSP 裝訂),它可以讓服務器預先訪問 CA 獲取 OCSP 響應,然後在握手時隨着證書一起發給客戶端,免去了客戶端連接 CA 服務器查詢的時間。

五、會話複用

  到這裏,我們已經討論了四種 HTTPS 優化手段(硬件優化、軟件優化、協議優化、證書優化),那麼,還有沒有其他更好的方式呢?

  我們再回想一下 HTTPS 建立連接的過程:先是 TCP 三次握手,然後是 TLS 一次握手。這後一次握手的重點是算出主密鑰“Master Secret”,而主密鑰每次連接都要重新計算,未免有點太浪費了,如果能夠把“辛辛苦苦”算出來的主密鑰緩存一下“重用”,不就可以免去了握手和計算的成本了嗎?

  這種做法就叫“會話複用”(TLS session resumption),和 HTTP Cache 一樣,也是提高 HTTPS 性能的“大殺器”,被瀏覽器和服務器廣泛應用

  會話複用分兩種,第一種叫“Session ID”,就是客戶端和服務器首次連接後各自保存一個會話的 ID 號,內存裏存儲主密鑰和其他相關的信息。當客戶端再次連接時發一個 ID 過來,服務器就在內存裏找,找到就直接用主密鑰恢復會話狀態,跳過證書驗證和密鑰交換,只用一個消息往返就可以建立安全通信。

六、會話票證

  “Session ID”是最早出現的會話複用技術,也是應用最廣的,但它也有缺點,服務器必須保存每一個客戶端的會話數據,對於擁有百萬、千萬級別用戶的網站來說存儲量就成了大問題,加重了服務器的負擔。於是,又出現了第二種“Session Ticket”方案。

  它有點類似 HTTP 的 Cookie,存儲的責任由服務器轉移到了客戶端,服務器加密會話信息,用“New Session Ticket”消息發給客戶端,讓客戶端保存。

  重連的時候,客戶端使用擴展“session_ticket”發送“Ticket”而不是“Session ID”,服務器解密後驗證有效期,就可以恢復會話,開始加密通信。

  不過“Session Ticket”方案需要使用一個固定的密鑰文件(ticket_key)來加密 Ticket,爲了防止密鑰被破解,保證“前向安全”,密鑰文件需要定期輪換,比如設置爲一小時或者一天。

七、預共享密鑰

  “False Start”“Session ID”“Session Ticket”等方式只能實現 1-RTT,而 TLS1.3 更進一步實現了“0-RTT”,原理和“Session Ticket”差不多,但在發送 Ticket 的同時會帶上應用數據(Early Data),免去了 1.2 裏的服務器確認步驟,這種方式叫“Pre-shared Key”,簡稱爲“PSK”。

  但“PSK”也不是完美的,它爲了追求效率而犧牲了一點安全性,容易受到“重放攻擊”(Replay attack)的威脅。黑客可以截獲“PSK”的數據,像復讀機那樣反覆向服務器發送。

  解決的辦法是隻允許安全的 GET/HEAD 方法,在消息里加入時間戳、“nonce”驗證,或者“一次性票證”限制重放。

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