基於 Nginx 的 HTTPS 性能優化

前言

分享一個卓見雲的較多客戶遇到HTTPS優化案例。javascript

隨着相關瀏覽器對HTTP協議的「不安全」、紅色頁面警告等嚴格措施的出臺,以及向 iOS 應用的 ATS 要求和微信、支付寶小程序強制 HTTPS 需求,以及在合規方面如等級保護對傳輸安全性的要求都在推進 HTTPS 的發展。css

雖然 HTTPS 優化了網站訪問體驗(防劫持)以及讓傳輸更加安全,可是不少網站主趕鴨子上架式的使用了 HTTPS 後每每都會遇到諸如:頁面加載速度變慢、服務器負載太高以及證書過時不及時更新等問題。html

因此本文就來探討一下 HTTPS 的優化實踐。java

選型

其實像 Apache Httpd、LigHttpd、Canddy 等 Web 服務軟件均可以設置 HTTPS,可是在相應的擴展生態和更新率上都不如 Nginx。 Nginx 做爲大型互聯網網站的 Web 入口軟件有着普遍的支持率,例如阿里系的 Tengine、CloudFlare 的 cloudflare-nginx、又拍雲用的 OpenResty 都是基於 Nginx 而來的,Nginx 是接受過大規模訪問驗證的。同時你們也將本身開發的組件回饋給 Nginx 社區,讓 Nginx 有着很是良好的擴展生態。nginx

image

​ 圖1-1 Nginx 在全網的使用狀況git

因此說 Nginx 是一款很好的 Web 服務軟件,選擇 Nginx 在提高性能的同時能極大的下降咱們的擴展成本。github

新功能

圍繞 Web 服務已經有很是多的新功能須要咱們關注並應用了,這裏先羅列相關新功能。算法

HTTP/2

相比廉頗老矣的 HTTP/1.x,HTTP/2 在底層傳輸作了很大的改動和優化包括有:json

  1. 每一個服務器只用一個鏈接,節省屢次創建鏈接的時間,在TLS上效果尤其明顯
  2. 加速 TLS 交付,HTTP/2 只耗時一次 TLS 握手,經過一個鏈接上的多路利用實現最佳性能
  3. 更安全,經過減小 TLS 的性能損失,讓更多應用使用 TLS,從而讓用戶信息更安全

image

在 Akamai 的 HTTP/2 DEMO中,加載300張圖片,HTTP/2 的優越性極大的顯現了出來,在 HTTP/1.X 須要 14.8s 的操做中,HTTP/2 僅需不到1s。ubuntu

HTTP/2 如今已經得到了絕大多數的現代瀏覽器的支持。只要咱們保證 Nginx 版本大於 1.9.5 便可。固然建議保持最新的 Nginx 穩定版本以便更新相關補丁。同時 HTTP/2 在現代瀏覽器的支持上還須要 OpenSSL 版本大於 1.0.2。

TLS 1.3

和 HTTP/1.x 同樣,目前受到主流支持的 TLS 協議版本是 1.1 和 1.2,分別發佈於 2006年和2008年,也都已經落後於時代的需求了。在2018年8月份,IETF終於宣佈TLS 1.3規範正式發佈了,標準規範(Standards Track)定義在 rfc8446。

image
image

TLS 1.3 相較以前版本的優化內容有:

  1. 握手時間:同等狀況下,TLSv1.3 比 TLSv1.2 少一個 RTT
  2. 應用數據:在會話複用場景下,支持 0-RTT 發送應用數據
  3. 握手消息:從 ServerHello 以後都是密文。
  4. 會話複用機制:棄用了 Session ID 方式的會話複用,採用 PSK 機制的會話複用。
  5. 密鑰算法:TLSv1.3 只支持 PFS (即徹底前向安全)的密鑰交換算法,禁用 RSA 這種密鑰交換算法。對稱密鑰算法只採用 AEAD 類型的加密算法,禁用CBC 模式的 AES、RC4 算法。
  6. 密鑰導出算法:TLSv1.3 使用新設計的叫作 HKDF 的算法,而 TLSv1.2 是使用PRF算法,稍後咱們再來看看這兩種算法的差異。

總結一下就是在更安全的基礎上還作到了更快,目前 TLS 1.3 的重要實現是 OpenSSL 1.1.1 開始支持了,而且 1.1.1 仍是一個 LTS 版本,將來的 RHEL八、Debian10 都將其做爲主要支持版本。在 Nginx 上的實現須要 Nginx 1.13+。

Brotli

Brotli 是由 Google 於 2015 年 9 月推出的無損壓縮算法,它經過用變種的 LZ77 算法,Huffman 編碼和二階文本建模進行數據壓縮,是一種壓縮比很高的壓縮方法。

根據Google 發佈的研究報告,Brotli 具備以下特色:

  1. 針對常見的 Web 資源內容,Brotli 的性能要比 Gzip 好 17-25%;
  2. Brotli 壓縮級別爲 1 時,壓縮速度是最快的,並且此時壓縮率比 gzip 壓縮等級爲 9(最高)時還要高;
  3. 在處理不一樣 HTML 文檔時,brotli 依然提供了很是高的壓縮率;

在兼容 GZIP 的同時,相較 GZIP:

  1. JavaScript 上縮小 14%
  2. HTML上縮小 21%
  3. CSS上縮小 17%

Brotli 的支持必須依賴 HTTPS,不過換句話說就是隻有在 HTTPS 下才能實現 Brotli。

ECC 證書

橢圓曲線密碼學(Elliptic curve cryptography,縮寫爲ECC),一種創建公開金鑰加密的算法,基於橢圓曲線數學。橢圓曲線在密碼學中的使用是在1985年由Neal Koblitz和Victor Miller分別獨立提出的。

內置 ECDSA 公鑰的證書通常被稱之爲 ECC 證書,內置 RSA 公鑰的證書就是 RSA 證書。因爲 256 位 ECC Key 在安全性上等同於 3072 位 RSA Key,加上 ECC 運算速度更快,ECDHE 密鑰交換 + ECDSA 數字簽名無疑是最好的選擇。因爲同等安全條件下,ECC 算法所需的 Key 更短,因此 ECC 證書文件體積比 RSA 證書要小一些。

ECC 證書不只僅能夠用於 HTTPS 場景當中,理論上能夠代替全部 RSA 證書的應用場景,如 SSH 密鑰登錄、SMTP 的 TLS 發件等。

不過使用 ECC 證書有兩個點須要注意:

1、 並非每個證書類型都支持的,通常商業證書中帶加強型字眼的才支持ECC證書的簽發。

image

2、 ECC證書在一些場景中可能還不被支持,由於一些產品或者軟件可能還不支持 ECC。 這時候就要虛線解決問題了,例如針對部分舊操做系統和瀏覽器不支持ECC,能夠經過ECC+RSA雙證書模式來解決問題。

安裝

下載源碼

綜合上述咱們要用到的新特性,咱們整合一下需求:

HTTP/2 要求 Nginx 1.9.5+,,OpenSSL 1.0.2+

TLS 1.3 要求 Nginx 1.13+,OpenSSL 1.1.1+

Brotli 要求 HTTPS,並在 Nginx 中添加擴展支持

ECC 雙證書 要求 Nginx 1.11+

這裏 Nginx,我我的推薦 1.15+,由於 1.14 雖然已經能支持TLS1.3了,可是一些 TLS1.3 的進階特性還只在 1.15+ 中提供。

而後咱們定義一下版本號:

# Version OpenSSLVersion='openssl-1.1.1a'; nginxVersion='nginx-1.14.1';

建議去官網隨時關注最新版:

http://nginx.org/en/download.html

https://www.openssl.org/source/

https://github.com/eustas/ngx_brotli/releases

Nginx

cd /opt wget http://nginx.org/download/$nginxVersion.tar.gz tar xzf $nginxVersion.tar.gz

OpenSSL

cd /opt wget https://www.openssl.org/source/$OpenSSLVersion.tar.gz tar xzf $OpenSSLVersion.tar.gz

Brotli

cd /opt git clone https://github.com/eustas/ngx_brotli.git cd ngx_brotli git submodule update --init --recursive

編譯

cd /opt/$nginxVersion/ ./configure \ --prefix=/usr/local/nginx \ ## 編譯後安裝的目錄位置 --with-openssl=/opt/$OpenSSLVersion \ ## 指定單獨編譯入 OpenSSL 的源碼位置 --with-openssl-opt=enable-tls1_3 \ ## 開啓 TLS 1.3 支持 --with-http_v2_module \ ## 開啓 HTTP/2 --with-http_ssl_module \ ## 開啓 HTTPS 支持 --with-http_gzip_static_module \ ## 開啓 GZip 壓縮 --add-module=/opt/ngx_brotli ## 編譯入 ngx_BroTli 擴展 make && make install ## 編譯並安裝

後續還有相關變量設置和設置服務、開啓啓動等步驟,篇幅限制就省略了,這篇文章有介紹在 Ubuntu 下的 Nginx 編譯:https://www.mf8.biz/ubuntu-nginx/ 。

配置

接下來咱們須要修改配置文件。

HTTP2

listen 443 ssl http2;

只要在 server{}  下的lisen 443 ssl 後添加 http2 便可。並且從 1.15 開始,只要寫了這一句話就不須要再寫 ssl on 了,不少小夥伴可能用了 1.15+ 之後衍用原配置文件會報錯,就是由於這一點。

TLS 1.3

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

若是不打算繼續支持 IE8,或者一些合規的要求,能夠去掉TLSv1

而後咱們再修改對應的加密算法,加入TLS1.3引入的新算法:

ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;

若是不打算繼續支持 IE8,能夠去掉包含 3DES 的 Cipher Suite。

默認狀況下 Nginx 由於安全緣由,沒有開啓 TLS 1.3 0-RTT,能夠經過添加 ssl_early_data on; 指令開啓 0-RTT的支持。

————

實驗性嘗試

衆所周知,TLS1.3 因爲更新了好久,不少瀏覽器的舊版本依舊只支持 Draft 版本,如 23 26 28 分別在 Chrome、FirFox 上有支持,反而正式版因爲草案出來好久,致使TLS1.3在瀏覽器上兼容性很多太好。

可使用 https://github.com/hakasenyang/openssl-patch/ 提供的 OpenSSL Patch 讓 OpenSSL 1.1.1 同時支持草案23,26,28和正式版輸出。 不過因爲不是官方腳本,穩定性和安全性有待考量。

ECC雙證書

雙證書配置的很簡單了,保證域名的證書有RSA和ECC各一份便可。

##證書部分 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC證書 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密鑰 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA證書 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密鑰

Brotli

須要在對應配置文件中,添加下面代碼便可:

brotli on; brotli_comp_level 6; brotli_min_length 1k; brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;

爲了防止你們看糊塗了,放一個完整的 server{}供你們參考:

server { listen 443 ssl http2; # 開啓 http/2 server_name mf8.biz www.mf8.biz; #證書部分 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.crt; #ECC證書 ssl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz-ecc.key; #ECC密鑰 ssl_certificate /usr/local/nginx/conf/ssl/www.mf8.biz.crt; #RSA證書 sl_certificate_key /usr/local/nginx/conf/ssl/www.mf8.biz.key; #RSA密鑰 #TLS 握手優化 ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; keepalive_timeout 75s; keepalive_requests 100; #TLS 版本控制 ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5'; # 開啓 1.3 o-RTT ssl_early_data on; # GZip 和 Brotli gzip on; gzip_comp_level 6; gzip_min_length 1k; gzip_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype; brotli on; brotli_comp_level 6; brotli_min_length 1k; brotli_types text/plain text/css text/xml text/javascript text/x-component application/json application/javascript application/x-javascript application/xml application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype; location / { root html; index index.html index.htm; } }

先驗證一下配置文件是否有誤:

nginx -t

若是反饋的是:

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

就能夠重啓 Nginx ,而後到對應網站中去查看效果了。

驗證

HTTP/2

經過瀏覽器的開發者工具,咱們能夠在 Network 欄目中看到 Protocol 中顯示 h2 有無來判斷。

image

TLS 1.3

老地方,咱們能夠經過瀏覽器的開發者工具 中的 Security 欄目看到 Connection 欄目下是否有顯示 TLS 1.3

image

ECC 雙證書

ECC 雙證書配置了之後無非就是在舊瀏覽器設別上的驗證了。這裏用足夠老的上古XP虛擬機來給你們證實一波。

XP系統上:

image

現代操做系統上的:

image

Brotli

經過瀏覽器的開發者工具,咱們能夠在 Network 欄目中,打開具體頁面的頭信息,看到 accept-encoding 中有 br 字眼就行。

image

總結

經過上述手段應該可讓 HTTPS 訪問的體驗優化很多,並且會比沒作 HTTPS 的網站訪問可能更快。

這樣的模式比較適合雲服務器單機或者簡單集羣上搭建,若是有應用 SLB 七層代理、WAF、CDN 這樣的產品可能會讓咱們的這些操做都白費。 咱們的這幾項操做都是自建的 Web 七層服務,若是有設置 SLB 七層代理、WAF、CDN 這樣設置在雲服務器以前就會被覆蓋掉。

因爲 SLB 七層和CDN這樣的產品會更加追求普遍的兼容性和穩定性並不會第一時間就用上上述的這些新特性(HTTP/2 是廣泛有的),可是他們都配備了阿里雲的 Tengine 的外部專用算法加速硬件如 Intel® QuickAssist Technology(QAT) 加速器能夠顯著提升SSL/TLS握手階段性能。 全部 HTTPS 的加密解密都在 SLB 或 CDN 上完成,而不會落到ECS上,能夠顯著下降 ECS 的負載壓力,而且提高訪問體驗。

目前雲上的網絡產品中能支持四層的都是能夠繼續兼容咱們這套設計的,例如:SLB 的四層轉發(TCP UDP)、DDOS高防的四層轉發。

 

原文連接本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索