Nginx 開啟 https 雙證書指南
前言
前幾天某某在 telegram 里提起 nginx 最新的 mainline 版本已經支持了雙證書, 想起自己 Aliyun 上的 nginx 已經有一段日子沒更新了, 趕緊上 NG 官網 看看有什么大新聞.
CHANGELOG 中截取的一段:
*) Feature: the "ssl_certificate" and "ssl_certificate_key" directives can be specified multiple times to load certificates of different types (for example, RSA and ECDSA).
ECDSA (橢圓曲線數字簽名算法) 就是我們所說的 ECC 證書了, 相比 RSA, ECC 證書具有安全性高, 處理速度更快的優點, 尤其適合在移動設備上使用. 但是其唯一的缺點就是兼容性問題, 古代的 XP 和 Android2.3 不支持這種加密方式.
于是雙證書就出現了. 它可以在 TLS 握手的時候根據客戶端支持的加密方法選擇對應的證書, 以向下兼容古代客戶端.
升級 Nginx
當前最新的 nginx 版本為 1.11.1 // 全是 1
由于 Chrome 在 51 版本之后對 HTTP/2 協議僅支持 ALPN, 該特性需要 nginx 在編譯的時候 (with) 使用 openssl 1.0.2g 及以上的版本(推薦最新的 1.0.2h, 免受 CVE-2016-2107 的影響). 但是 openssl 作為 linux 中關鍵的一個組件, 隨意升級會出現很多不確定因素, 所以我選擇手動編譯安裝 nginx 并使用 --with-openssl 來指定特定版本的 openssl.
wget https://github.com/openssl/openssl/archive/OpenSSL_1_0_2h.tar.gz tar xzvf OpenSSL_1_0_2h.tar.gz wget http://nginx.org/download/nginx-1.11.1.tar.gz tar xzvf nginx-1.11.1.tar.gz cd nginx-1.11.1/ nginx -V ./configure --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --add-module=../nginx-ct-1.2.0 --with-openssl=../OpenSSL_1_0_2h --with-http_v2_module --with-http_ssl_module make make install service nginx restart
這里的 configure 配置僅供參考, 添加的 nginx-ct 模塊是為開啟Certificate Transperancy 策略做的準備.
啟用雙證書
在啟用之前, 先要確保你有對應域名的兩張證書, 一張 ECC 證書, 另一張 RSA 證書.
我的 ECC 證書是由 Let's Encrypt 簽發的, 使用了最新的 X3 中間證書; RSA 證書則是 AlphaSSL 的泛解析證書.
nginx 配置如下
ssl_certificate ssl/letsencrypt-ecc/chained.pem; ssl_certificate_key ssl/letsencrypt-ecc/domain.key; ssl_certificate ssl/all.zeroling.com.crt; ssl_certificate_key ssl/all.zeroling.com.key; ssl_prefer_server_ciphers on; ssl_ciphers EECDH+CHACHA20:EECDH+ECDSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_ciphers 中同時添加了對 ECDSA 和 RSA 的支持
其它策略
HPKP
由于我的 RSA 證書簽發者與 ECC 證書的不是同一個, 所以在 HPKP 頭中, 需要同時指定兩份證書的中間證書.
Public-Key-Pins 'pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; pin-sha256="amMeV6gb9QNx0Zf7FtJ19Wa/t2B7KpCF/1n2Js3UuSU="; max-age=2592000; includeSubDomains';
如果你的兩份證書是由同一個簽發者簽名的, 只需要指定一次即可, 也就是說完全可以不用修改這項配置, 與單證書的時候保持一致肯定沒錯.
HSTS
恩, 這個不影響.
CT(Certificate Transperancy)
前面我編譯 nginx 的時候添加了 nginx-ct 模塊, 這個模塊可以幫助你很快的開啟 CT 策略, 具體開啟的方法可以參考 qgy 大神的 這篇文章 , 唯一要注意的地方是, 如果你的服務器在天朝, 目前還是無法請求 googleapis 的 CT Logs 服務器的, 所以你可以使用一些特殊姿勢來完成, 比如把證書傳到國外 VPS 驗證后, 再把 sct 文件傳回來.
對于開啟了雙證書的網站, 你只需要保證兩本證書的所有 sct 文件都放在一個目錄下, 并在 nginx 中配置 ssl_ct_static_scts 為該路徑即可, 瀏覽器會自動識別有效的 CT 信息.
ssl_ct on; ssl_ct_static_scts ssl/sct;
OCSP stapling
這里其實有個坑, 詳細可以看這篇文章: 從無法開啟 OCSP Stapling 說起
我先來說結論:
Let's Encrypt 的 OCSP 服務也沒有返回 Certificate,所以使用 Let's Encrypt 證書,開啟 OCSP Stapling 也無需配置 ssl_trusted_certificate
如果 OCSP Response 包含了 Certificate 信息,并且 Nginx 配置了 ssl_stapling_verify on ,那么需要確保正確配置了 ssl_trusted_certificate 參數,這個參數應該指向一個包含根證書、中間證書的文件(順序是子證書在上、父證書在下),否則 OCSP Stapling 無法生效。這時候 Nginx 的 error_log 中會出現類似這樣的錯誤:
我的證書鏈中, ECC 的 let's encrypt 證書無需指定 ssl_trusted_certificate , 也就是說即使指定也不會生效; 而 RSA 的 AlphaSSL 證書需要指定 ssl_trusted_certificate 為一個包含根證書、中間證書的文件.
ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate ssl/all.zeroling.com.server-middle-root.crt;
于是我的配置如下, 如果你的雙證書都是 Let's Encrypt 簽發的, 則 ssl_stapling_verify 和 ssl_trusted_certificate 兩個配置可以忽略,完全不影響開啟 OCSP Stapling。
測試
配置完成后, 趕緊到 ssllab 測試一下是否配置正確吧.
在 Handshake Simulation 中, 如果可以看到 EC 和 RSA 同時出現在不同的機器上, 就說明成功了.
這是 本站的測試結果 .
來自: http://www.zeroling.com/nginx-kai-qi-https-shuang-zheng-shu-zhi-nan/