優化HTTPS

HTTP/2

HTTP 2.0即超文本傳輸協議 2.0,是下一代HTTP協議。是由互聯網工程任務組(IETF)的Hypertext Transfer Protocol Bis (httpbis)工作小組進行開發。是自1999年http1.1發佈後的首個更新,HTTP/2 協議是從 SPDY 演變而來,SPDY 已經完成了使命並很快就會退出歷史舞臺(例如 Chrome 在「2016 年初結束對 SPDY 的支持」;Nginx在版本1.9.5+,Apache在版本2.4.16+都已經全面支持HTTP/2。

上圖是Akamai的HTTP/2 DEMO,通過加載300張圖片,對比HTTP/1.1和HTTP/2,首先直觀地感受一下HTTP/2,下來解釋一下這個感受的原因,即HTTP/2新特性:

  • 二進制分幀

  • 首部壓縮

  • 流量控制

  • 多路複用

  • 請求優先級

  • 服務器推送

二進制分幀

二進制分幀層,是HTTP2.0性能增強的核心

HTTP 1.x在應用層以純文本的形式進行通信,HTTP2.0在不改變HTTP1.x的語義、方法、狀態碼、URL以及首部字段的情況下,爲了突破原有性能限制,在應用層(HTTP)和傳輸層(TCP)之間增加了一個二進制分幀層。HTTP2.0將所有的傳輸信息分割爲更小的消息和幀,並對它們採用二進制格式編碼,如下圖所示

這裏引入一個新的通信單位:幀

幀是HTTP 2.0通信的最小單位,包括幀首部、流標識符、優先值和幀淨荷等

其中,幀類型可以分爲:

  • DATA:用於傳輸HTTP消息體

  • HEADERS:用於傳輸首部字段

  • SETTINGS:用於約定客戶端和服務端的配置數據。比如設置初識的雙向流量控制窗口大小

  • WINDOW_UPDATE:用於調整個別流或個別連接的流量

  • PRIORITY:用於指定或重新指定引用資源的優先級

  • RST_STREAM:用於通知流的非正常終止

  • PUSH_ PROMISE:服務端推送許可

  • PING:用於計算往返時間,執行“ 活性” 檢活

  • GOAWAY:用於通知對端停止在當前連接中創建流

標誌位,用於不同的幀類型定義特定的消息標誌。比如DATA幀就可以使用End Stream: true表示該條消息通信完畢;流標識位表示幀所屬的流ID;優先值用於HEADERS幀,表示請求優先級;R表示保留。

下面是抓包的一個HEADERS幀:

另外一個兩個要說一下的概念:消息和流

消息是指邏輯上的HTTP消息(請求/響應),一系列數據幀組成一個完整的消息,比如一系列DATA幀和一個HEADERS幀組成了請求消息。

流是鏈接中的一個虛擬信道,可以承載雙向消息傳輸,每個流有唯一證書標識符,爲了防止兩端流ID衝突,客戶端發起的流具有奇數ID,服務端發起的流具有偶數ID。

所有HTTP 2.0通信都在一個TCP鏈接上完成,這個鏈接可以承載任意數量的雙向數據流Stream。相應地,每個數據流以消息的形式發送,而消息由一個或多個幀組成,這些幀可以亂序發送,然後根據每個幀首部的流標識符重新組裝。

二進制分幀主要是爲HTTP2.0其他特性提供基礎。它能把一個數據劃分封裝爲更小更便捷的數據。首先是在單鏈多資源方式中,減少服務端的鏈接壓力,內存佔用更少,鏈接吞吐量更大;另一方面,由於TCP鏈接的減少而使網絡擁塞狀態得以改善,同時慢啓動時間減少,使擁塞和丟包恢復的速度更快。

首部壓縮

HTTP1.x每次通信(請求或響應)都會攜帶首部信息用於描述資源屬性。而HTTP2.0在客戶端和服務端之間使用首部表來跟蹤和存儲之前發送的鍵值對,首部表在連接過程中始終存在,新增的鍵值對會更新到表尾,因此不需要每次通信都攜帶首部,請求與響應首部的定義在HTTP2.0中基本沒有變。

另外HTTP2.0使用了首部壓縮技術,壓縮算法採用HPACK,讓報頭更緊湊、更快速傳輸,有利於移動網絡環境。需要注意的是,HTTP2.0的首部壓縮,與我們常用的gzip等報文內容壓縮不衝突。

流量控制

HTTP/2.0 “流”的流量控制的目標是:在不改變協議的情況下允許使用多種流量控制算法

  • 流量控制是特定於一個連接的。每種類型的流量控制都是在單獨的一跳的兩個端點之間的,並不是在整個端到端的路徑上的。(這裏的一跳指的是HTTP連接的一跳,而不是IP路由的一跳)

  • 流量控制是基於WINDOW_UPDATE幀的。接收方公佈自己打算在每個流以及整個連接上分別接收多少字節。這是一個以信用爲基礎的方案。

  • 流量控制是有方向的,由接收者全面控制。接收方可以爲每個流和整個連接設置任意的窗口大小。發送方必須尊重接收方設置的流量控制限制。客戶方、服務端和中間代理作爲接收方時都獨立地公佈各自的流量控制窗口,作爲發送方時都遵守對端的流量控制設置。

  • 無論是新流還是整個連接,流量控制窗口的初始值是65535字節。

  • 幀的類型決定了流量控制是否適用於幀。目前,只有DATA幀服從流量控制,所有其它類型的幀並不消耗流量控制窗口的空間。這保證了重要的控制幀不會被流量控制阻塞。

  • 流量控制不能被禁用。

  • HTTP/2只定義了WINDOW_UPDATE幀的格式和語義,並沒有規定接收方如何決定何時發送幀、發送什麼樣的值,也沒有規定發送方如何選擇發送包。具體實現可以選擇任何滿足需求的算法。

多路複用

在HTTP1.1中,瀏覽器客戶端在同一時間,針對同一域名下的請求有一定數量的限制。超過限制數目的請求會被阻塞,而HTTP2.0中的多路複用優化了這一性能。

基於二進制分幀層,HTTP2.0可以在共享TCP連接的基礎上,同時發送請求和響應。HTTP消息被分解爲獨立的幀,而不破壞消息本身的語義,交錯發送出去,最後在另一端根據流ID和首部將他們重新組合。對比看一下HTTP1.x和HTTP2.0,這裏不考慮HTTP1.x的pipeline機制。

HTTP2.0成功解決了HTTP1.x的隊首阻塞問題(TCP層的阻塞仍無法解決),同時,也不需要通過pipeline機制多條TCP連接來實現並行請求與響應。減少了TCP連接數對服務器性能有很大提升,同時也消除不必要的延遲,從而減少頁面加載的時間。

請求優先級

把HTTP消息分爲很多獨立幀之後,就可以通過優化這些幀的交錯和傳輸順序進一步優化性能。

每個流都可以帶有一個31bit的優先值:0表示最高優先級;2的31次方-1表示最低優先級。

客戶端明確指定優先級,服務端可以根據這個優先級作爲交互數據的依據,比如客戶端優先設置爲.css>.js>.jpg。服務端按此順序返回結果更加有利於高效利用底層連接,提高用戶體驗。然而,在使用請求優先級時應注意服務端是否支持請求優先級,是否會引起隊首阻塞問題,比如高優先級的 慢響應請求會阻塞其他資源的交互。

服務器推送

HTTP2.0增加了服務端推送功能,服務端可以根據客戶端的請求,提前返回多個響應,推送額外的資源給客戶端

如下圖,客戶端請求stream 1(/page.html)。服務器在返回stream 1的消息的同時推送了stream 2(/script.js)和stream4(/style.css)

  • PUSH_PROMISE幀是服務端向客戶端有意推送資源的信號。

  • PUSH_PROMISE幀中只包含預推送資源的首部。如果客戶端對PUSH_PROMISE幀沒有意見,服務端在PUSH_PROMISE幀後發送響應的DATA幀。如果客戶端已經緩存了該資源,不需要推送,可以拒絕PUSH_PROMISE幀。

  • PUSH-PROMISE必須遵循請求-響應原則,只能藉着對請求的響應推送資源。

  • PUSH_PROMISE幀必須在返回響應之前發送,以免客戶端出現競態條件(競態條件是指在多線程的情況下不同的執行順序會導致計算機執行出不同的結果正確性不同)

  • HTTP2.0連接後,客戶端與服務端交換SETTINGS幀,藉此限定雙向併發的最大數量。因此,客戶端可以限定推送流的數量,或者通過把這個只設置爲0來完全禁止服務器推送。

  • 所有推送的資源都必須遵守同源策略。換句話說,服務器不能隨便將第三方資源推送給客戶端,而必須是經過雙方的確認纔行。

 

HTTP/2現在已經獲得絕大多數瀏覽器的支持,不過在使用過程中HTTP/2需要使用1.0.1e之後的openssl版本,通過nginx -V,可以查看nginx的openssl版本,如果版本低,重新編譯nginx即可。

 

那麼在nginx中如何配置支持HTTP/2?很簡單,只需要在server中的listen部分添加http2即可。

怎麼測試http2是否已開啓,方法很多,這裏介紹三種方法:

1、瀏覽器開發者工具

2、Chrome擴展HTTP/2 and SPDY indicator

3、命令行客戶端nghttp

另外HTTP/2的服務器推送,需要nginx配置纔能有效利用。

通過http2_push指令配置

這種情況下,demo.html需要用到的資源style.css、image1.jpg和image2.jpg被推送到客戶端。資源少的情況下,我們可以這麼使用,但是資源多的情況下這種方式就不太現實。

自動將資源推送給客戶端

nginx支持攔截link預加載頭的約定,推送這寫頭中標識的資源,需要在配置中啓動預加載,配置http2_push_preload on

這裏也有一個問題,一般的靜態資源,我們都會設置緩存有效期。當客戶端資源在緩存有效期內的時候,我們強制推送靜態資源,只會增加服務器帶寬的壓力,所以我們需要指定客戶端是否需要這些資源,並且不太可能已經緩存過,可能的方法,就是客戶端在首次訪問時服務端推送,並在隨後的訪問請求中包含cookie,服務端通過cookie去判斷是否進行推送,就是有選擇的向客戶端推送資源,配置方法如下:

測試如下:

 

 

TLS 1.3

TLS(Transport Layer Security Protocol,傳輸層安全協議)主要目的是提供隱私和數據亮哥通信應用之間的完整性。該協議由兩層組成:TLS記錄協議(TLS Record)和TLS握手協議(TLS Handshake)。

TLS協議經過很多次版本的更新,目前低版本的TLS,如SSL 3.0/TLS 1.0等,存在許多嚴重漏洞,目前受到主流支持的TLS協議版本是1.1和1.2,但也都已經落後於時代的需求。在2018年8月份,IETF終於宣佈TLS 1.3規範正式發佈了,標準規範定義在rfc8446。

相較於之前的版本TLS優化內容有:

  • 相比過去的的版本,引入了新的密鑰協商機制 — PSK

  • 支持 0-RTT 數據傳輸,在建立連接時節省了往返時間

  • 廢棄了 3DES、RC4、AES-CBC 等加密組件,廢棄了 SHA1、MD5 等哈希算法

  • ServerHello 之後的所有握手消息採取了加密操作,可見明文大大減少

  • 不再允許對加密報文進行壓縮、不再允許雙方發起重協商

  • DSA 證書不再允許在 TLS 1.3 中使用

在https中,每個連接的TLS的握手是很消耗資源及時間的,所以TLS 1.3的優化,比之前的版本建立連接的時間少了一個RTT,同等情況下,節省了很多時間,提高了響應速度。

TLS 1.3需要openssl 1.1.1支持,在nginx上,需要nginx 1.13+支持。

在編譯nginx的時候,需要添加編譯參數--with-openssl-opt=enable-tls1_3來開啓TLS 1.3支持,並在配置中ssl_protocols中添加TLSv1.3,對應的TLS1.3引入了新的算法,所以ssl_ciphers也需要添加新算法

默認情況下nginx因爲安全原因,沒有開啓TLS 1.3的 0-RTT,可以通過指令ssl_early_data on來開啓。

ECC

 

ECC(Elliptic curve cryptography,橢圓曲線密碼學),一種建立公開密鑰的算法,基於橢圓曲線數學。

內置ECDSA公鑰的證書一般稱爲ECC證書,內置RSA公鑰的證書一般稱爲RSA證書。

ECC算法的數學理論非常深奧和複雜,在工程應用中比較難於實現,但它的單位安全強度相對較高,它的破譯或求解難度基本上是指數級的,黑客很難用通常使用的暴力破解的方法來破解。RSA算法的特點之一是數學原理相對簡單,在工程應用中比較易於實現,但它的單位安全強度相對較低。因此,ECC算法的可以用較少的計算能力提供比RSA加密算法更高的安全強度,有效地解決了“提高安全強度必須增加密鑰長度”的工程實現問題。

與RSA算法相比,ECC算法擁有一下優勢:

  • 更適合於移動互聯網:ECC加密算法的密鑰長度很短(256位),意味着佔用更少的存儲空間,更低的CPU開銷和佔用更少的帶寬。隨着越來越多的用戶使用移動設備來完成各種網上活動,ECC加密算法爲移動互聯網安全提供更好的客戶體驗。

  • 更好的安全性:ECC加密算法提供更強的保護,比目前的其他加密算法能更好的防止攻擊,使你的網站和基礎設施比用傳統的加密方法更安全,爲移動互聯網安全提供更好的保障。

  • 更好的性能:ECC加密算法需要較短的密鑰長度來提供更好的安全,例如,256位的ECC密鑰加密強度等同於3072位RSA密鑰的水平(目前普通使用的RSA密鑰長度是2048位)。其結果是你以更低的計算能力代價得到了更高的安全性。經國外有關權威機構測試,在Apache和IIS服務器採用ECC算法,Web服務器響應時間比RSA快十幾倍。

  • 更大的IT投資回報:ECC可幫助保護您的基礎設施的投資,提供更高的安全性,並快速處理爆炸增長的移動設備的安全連接。ECC的密鑰長度增加速度比其他的加密方法都慢(一般按128位增長,而 RSA則是倍數增長,如:1024 –2048--4096),將延長您現有硬件的使用壽命,讓您的投資帶來更大的回報。

不過使用ECC證書有兩個問題需要注意:

1、不是所有類型證書都支持ECC,一般需要商業證書的增強版本中才支持

2、一些舊的設備或瀏覽器不支持ECC,可能需要ECC+RSA雙證書的模式來使用

 

Brotli

Brotli是Google於2015年9月推出的無損壓縮算法,Brotli通過變種的LZ77算法、Huffman編碼以及二階文本建模等方式進行數據壓縮,與其他壓縮算法相比,它有者更高的壓縮效率。

更具Google發佈的報告指出,Brotli有一下特點:

 

  • 針對常見的 Web 資源內容,Brotli 的性能相比 Gzip 提高了 17-25%;

  • 當 Brotli 壓縮級別爲 1 時,壓縮率比 Gzip 壓縮等級爲 9(最高)時還要高;

  • 在處理不同 HTML 文檔時,Brotli 依然能夠提供非常高的壓縮率。

Brotli的支持必須依賴HTTPS,nginx支持Brotli必須編輯添加brotli模塊

brotli模塊源碼地址https://github.com/eustas/ngx_brotli.git,下載之後,在nginx編譯的時候通過編譯參數--add-module=/path/to/ngx_brotli進行編譯添加。添加之後通過配置文件中添加配置啓用brotli。

在開發者工具中查看headers:

 

趕快優化一下你的HTTPS吧!

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