轉載: 關於啟用 HTTPS 的一些經驗分享(二)
幾天前,一位朋友問我:都說推薦用 Qualys SSL Labs 這個工具測試 SSL 安全性,為什么有些安全實力很強的大廠家評分也很低?我認為這個問題應該從兩方面來看:1)國內用戶終端情況復雜,很多時候降低 SSL 安全配置是為了兼容更多用戶;2)確實有一些大廠家的 SSL 配置很不專業,尤其是配置了一些明顯不該使用的 CipherSuite。
我之前寫的《關於啟用 HTTPS 的一些經驗分享(一)》,主要介紹 HTTPS 如何與一些新出的安全規范配合使用,面向的是現代瀏覽器。而今天這篇文章,更多的是介紹啟用 HTTPS 過程中在老舊瀏覽器下可能遇到的問題,以及如何取舍。
SSL 版本選擇
TLS(Transport Layer Security,傳輸層安全)的前身是 SSL(Secure Sockets Layer,安全套接字層),它最初的幾個版本(SSL 1.0、SSL 2.0、SSL 3.0)由網景公司開發,從 3.1 開始被 IETF 標准化並改名,發展至今已經有 TLS 1.0、TLS 1.1、TLS 1.2 三個版本。TLS 1.3 改動會比較大,目前還在草案階段。
SSL 1.0 從未公開過,而 SSL 2.0 和 SSL 3.0 都存在安全問題,不推薦使用。Nginx 從 1.9.1 開始默認只支持 TLS 的三個版本,以下是 Nginx 官方文檔中對 ssl_protocols 配置的說明:
Syntax: ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];
Default: ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
Context: http, server
Enables the specified protocols. The TLSv1.1 and TLSv1.2 parameters work only when the OpenSSL library of version 1.0.1 or higher is used.
但不幸的是,IE 6 默認只支持 SSLv2 和 SSLv3(來源),也就是說 HTTPS 網站要支持 IE 6,就必須啟用 SSLv3。僅這一項就會導致 SSL Labs 給出的評分降為 C。
加密套件選擇
加密套件(CipherSuite),是在 SSL 握手中需要協商的很重要的一個參數。客戶端會在 Client Hello
中帶上它所支持的 CipherSuite 列表,服務端會從中選定一個並通過 Server Hello
返回。如果客戶端支持的 CipherSuite 列表與服務端配置的 CipherSuite 列表沒有交集,會導致無法完成協商,握手失敗。
CipherSuite 包含多種技術,例如認證算法(Authentication)、加密算法(Encryption)、消息認證碼算法(Message Authentication Code,簡稱為 MAC)、密鑰交換算法(Key Exchange)和密鑰衍生算法(Key Derivation Function)。
SSL 的 CipherSuite 協商機制具有良好的擴展性,每個 CipherSuite 都需要在 IANA 注冊,並被分配兩個字節的標志。全部 CipherSuite 可以在 IANA 的 TLS Cipher Suite Registry 頁面查看。
OpenSSL 庫支持的全部 CipherSuite 可以通過以下命令查看:
openssl ciphers -V | column -t
0xCC,0x14 - ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=ChaCha20-Poly1305 Mac=AEAD
... ...
0xCC,0x14
是 CipherSuite 的編號,在 SSL 握手中會用到。ECDHE-ECDSA-CHACHA20-POLY1305
是它的名稱,之后幾部分分別表示:用於 TLSv1.2,使用 ECDH 做密鑰交換,使用 ECDSA 做認證,使用 ChaCha20-Poly1305 做對稱加密,由於 ChaCha20-Poly1305 是一種 AEAD 模式,不需要 MAC 算法,所以 MAC 列顯示為 AEAD。
要了解 CipherSuite 的更多內容,可以閱讀這篇長文《TLS 協議分析 與 現代加密通信協議設計》。總之,在配置 CipherSuite 時,請務必參考權威文檔,如:Mozilla 的推薦配置、CloudFlare 使用的配置。
以上 Mozilla 文檔中的「Old backward compatibility」配置,以及 CloudFlare 的配置,都可以很好的兼容老舊瀏覽器,包括 Windows XP / IE6。
之前見到某個大廠家居然支持包含 EXPORT
的 CipherSuite,這些套件在上世紀由於美國出口限制而被弱化過,已被攻破,實在沒有理由再使用。
SNI 擴展
我們知道,在 Nginx 中可以通過指定不同的 server_name
來配置多個站點。HTTP/1.1 協議請求頭中的 Host
字段可以標識出當前請求屬於哪個站點。但是對於 HTTPS 網站來說,要想發送 HTTP 數據,必須等待 SSL 握手完成,而在握手階段服務端就必須提供網站證書。對於在同一個 IP 部署不同 HTTPS 站點,並且還使用了不同證書的情況下,服務端怎么知道該發送哪個證書?
Server Name Indication,簡稱為 SNI,是 TLS 的一個擴展,為解決這個問題應運而生。有了 SNI,服務端可以通過 Client Hello
中的 SNI 擴展拿到用戶要訪問網站的 Server Name,進而發送與之匹配的證書,順利完成 SSL 握手。
Nginx 在很早之前就支持了 SNI,可以通過 nginx -V
來驗證。以下是我的驗證結果:
./nginx -V
nginx version: nginx/1.9.9
built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
built with OpenSSL 1.0.2e-dev xx xxxx
TLS SNI support enabled
configure arguments: --with-openssl=../openssl --with-http_ssl_module --with-http_v2_module
然而,並不是所有瀏覽器都支持 SNI,以下是常見瀏覽器支持 SNI 的最低版本: