1. 程式人生 > >Nginx上部署HTTPS + HTTP2

Nginx上部署HTTPS + HTTP2

nginx

Nginx上部署HTTPS依賴OpenSSL庫和包含文件,即須先安裝好libssl-dev(或者OpenSSL),且ln -s /usr/lib/x86_64-linux-gnu/libssl.so /usr/lib/,然後在編譯配置Nginx時要指定--with-http_ssl_module和--with-http_v2_module。另外,若要在本地運行openssl命令,要安裝OpenSSL包,本人用的OpenSSL-1.0.2g。註:本文采用Ubuntu 16.04上的操作實例

  下圖展示了數字證書(HTTPS中使用的由CA簽名的公鑰證書)的簽名和驗證原理:技術分享

  • TLS保障信息傳輸安全:對於每一次新的對話(連接握手階段。這裏講的對話不是HTTP中涉及的應用層對話,而是TLS對話),客戶端和服務端都會協商一個對話密鑰和對稱加密算法(了解更多可參考“加密套件”“四次握手”相關內容)用來加減密信息,這樣就避免非對稱加減密耗時過長,運算速度更快;而Public/Private密鑰對只用於"pre-master key"的加解密。特別地,在連接斷開後,舊對話的恢復(兩種實現方法:session ID和session ticket)不屬於建立新的對話,無需協商一個新的對話密鑰和對稱加密算法。

  • HTTP2:HTTP2 基於SPDY設計,支持HTTPS。但HTTP2與SPDY不同的是,不強制使用 HTTPS,但目前還沒有瀏覽器支持;HTTP2 消息頭的壓縮算法采用 HPACK ,而非 SPDY 采用的 DELEFT。HTTP2基本兼容HTTP1.x的語義,只是改變了HTTP1.x的傳輸方式,在連接中是否使用HTTP2是通過協議協商(NPN、ALPN或Upgrade頭)來決定的。HTTP2擁有許多新特性:

  1. 二進制協議:HTTP2.0協議采用二進制格式,實現方便且健壯;HTTP1.x采用的是文本格式

  2. 頭部壓縮:HTTP/1.x 每次請求,都會攜帶大量冗余頭信息,浪費了很多帶寬資源,頭壓縮能夠很好的解決該問題

  3. 多路復用:多個請求和響應通過一個 TCP 連接並發完成,還支持請求優先級劃分和流控制

  4. Server Push:服務端可以主動把 JS 和 CSS 文件推送給客戶端,而不需要客戶端先解析 HTML 再發送這些請求。當客戶端需要的時候,它們已經在客戶端了

  下圖是HTTP2 Frame 格式:RFC7540 - Hypertext Transfer Protocol Version 2 (HTTP/2)

  技術分享

  技術分享

  • Nginx上部署HTTPS + HTTP2

  1. 自簽發證書:開發測試環境下可以在其他機器上去生成證書,然後再將所生成server.crt和server.key復制一份至Nginx的/usr/local/nginx/conf下即可

    $ cd /usr/local/nginx/conf
    $ openssl genrsa -des3 -out server.key 1024 #建議:2048$ openssl req -new -key server.key -out server.csr #證書簽名請求(CSR)
    $ cp server.key server.key.org
    $ openssl rsa -in server.key.org -out server.key
    $ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt #證書簽名
  2. 修改配置文件nginx.conf為減少CPU負載,建議只運行一個工作進程,並且開啟keep-alive。另外,version 0.6.7以上的Nginx ssl_certificate和ssl_certificate_key的默認關聯目錄為nginx.conf所在的目錄,默認文件名都為cert.pem

    技術分享

    worker_processes 1;
    server {
    
        server_name YOUR_DOMAINNAME_HERE;
        listen 443 ssl http2;# http2 is available only since OpenSSL version 1.0.2
        listen 80;
        if ($scheme = http) {
                rewrite ^(.*)$ https://$server_name$1 permanent;
        }
        ssl_certificate server.crt;
        ssl_certificate_key server.key;
        keepalive_timeout    70;
    }

    技術分享

  3. 重啟NginxHTTPS在Nginx上的部署至此已近完畢,然後就可以通過ht t ps : / / YO U R _ D OM A I N N A ME _ H E R E來訪問了。由於本例中采用自簽發證書(不同於CA自簽名的Root證書),在Chrome下將看到如圖警告信息,表明該證書不受信任。瀏覽器在默認情況下內置了一些CA機構的Root證書,這些證書受到絕對信任。

   技術分享

  另外,本人在Chromium 58.0.3029.110 和 Firefox 53.0.3 下均證實了HTTP2被成功啟用:

  技術分享

  • 私鑰保護:私鑰是重要的財產,盡可能限制能接觸到私鑰的人

  1. 在一臺可信的計算機上生成私鑰和CSR(Certificate Signing Requests)。有一些CA會為你生成密鑰和CSR,但這樣做明顯不妥

  2. 受密碼保護的密鑰可以阻止在備份系統中被截獲

  3. 在發現被截獲後,撤回老的證書,生成新的密鑰和證書

  4. 每年更新證書,總是使用最新的私鑰

  • 部署證書鏈:證書鏈(Certificate Chain)包括信任錨(CA 證書)和簽名證書,是由一系列 CA 證書發出的證書序列,最終以根 CA 證書結束;Web 瀏覽器已預先配置了一組瀏覽器自動信任的根 CA 證書,來自其他證書授權機構的所有證書都必須附帶證書鏈,以檢驗這些證書的有效性。在很多部署場景中,單一的服務器證書顯得不足,而多個證書則需要建立一個信任鏈。一個常見的問題是正確的配置了服務器證書但卻搞忘了包含其他所需要的證書。此外,雖然其他證書通常有很長的有效期,但它們也會過期,如果它們過期就會影響整個鏈條。一個無效證書鏈會導致服務器證書失效和客戶端瀏覽器報警告,這個問題有時候不是那麽容易被檢測到,因為有些瀏覽器可以自己重構一個完整的信任鏈而有些則不行。關於Nginx上部署證書鏈:

    if you have a chain certificate file (sometimes called an intermediate certificate)
    you don‘t specify it separately like you do in Apache. Instead you need to add the 
    information from the chain cert to the end of your main certificate file. This can be done 
    by typing "cat chain.crt >> mysite.com.crt" on the command line. Once that is done you
    won‘t use the chain cert file for anything else, you just point Nginx to the main certificate file

   下圖展示了證書鏈的工作原理:

  技術分享

  • Nginx上SSL配置指令說明下邊只列舉了部分,更多配置項可參考 http://www.nginx.cn/doc/optional/ssl.html。

  1. ssl開啟HTTPS

    syntax:ssl [on|off]

    default:ssl off

    context:main, server

  2. ssl_certificate證書文件,默認證書和密鑰都位於cert.pem中,該文件還可以包含其他證書。自version 0.6.7起,ssl_certificate的默認關聯目錄為nginx.conf所在的目錄。

    syntax:ssl_certificate file

    default:ssl_certificate cert.pem

    context:main, server

  3. ssl_certificate_key:證書密鑰文件,默認密鑰位於cert.pem中。自version 0.6.7起,ssl_certificate_key的默認關聯目錄為nginx.conf所在的目錄。

    syntax:ssl_certificate_key file

    default:ssl_certificate_key cert.pem

    context:main, server

  4. ssl_client_certificate:Indicates file with certificates CA in PEM format, utilized for checking the client certificates.

    syntax:ssl_client_certificate file

    default:none

    context:main, server

  5. ssl_dhparamIndicates file with Diffie-Hellman parameters in PEM format, utilized for negotiating TLS session keys.

    syntax: ssl_dhparam file

    default: none

    context: main, server

  6. ssl_ciphers:Directive describes the permitted ciphers. Ciphers are assigned in the formats supported by OpenSSL.

    syntax: ssl_ciphers file

    default: ssl_ciphers ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP

    context: main, server

    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;

    Complete list can be looked with the following command:

    openssl ciphers

  7. ssl_prefer_server_ciphers:Requires protocols SSLv3 and TLSv1 server ciphers be preferred over the client‘s ciphers.

    syntax: ssl_prefer_server_ciphers [on|off]

    default: ssl_prefer_server_ciphers off

    context: main, server

  8. ssl_protocols:Directive enables the protocols indicated. TLS v1.0以上的版本是比較安全的,最好是棄用SSLv3以下的版本,SSLv2以下堅決不用

    syntax: ssl_protocols [SSLv2] [SSLv3] [TLSv1]

    default: ssl_protocols SSLv2 SSLv3 TLSv1

    context: main, server

  9. ssl_session_cache:The directive sets the types and sizes of caches to store the SSL sessions.

    syntax:ssl_session_cache off|none|builtin:size and/or shared:name:size

    default:ssl_session_cache off

    context:main, server

    ssl_session_cache builtin:1000 shared:SSL:10m;

  10. ssl_session_timeout:Assigns the time during which the client can repeatedly use the parameters of the session, which is stored in the cache.

    syntax:ssl_session_timeout time

    default:ssl_session_timeout 5m

    context:main, server


Nginx上部署HTTPS + HTTP2