設定 HTTPS 伺服器
HTTPS 伺服器最佳化 SSL 憑證鏈 單一 HTTP/HTTPS 伺服器 基於名稱的 HTTPS 伺服器 具有多個名稱的 SSL 憑證 伺服器名稱指示 (Server Name Indication) 相容性 |
要設定 HTTPS 伺服器,必須在 server 區塊中的監聽 sockets 上啟用 ssl
參數,並指定伺服器憑證和私密金鑰檔案的位置
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ... }
伺服器憑證是公開實體。它會傳送給每個連線到伺服器的用戶端。私密金鑰是安全實體,應儲存在存取受限的檔案中,但 nginx 的主要程序必須能夠讀取它。私密金鑰也可以與憑證儲存在同一個檔案中
ssl_certificate www.example.com.cert; ssl_certificate_key www.example.com.cert;
在這種情況下,檔案存取權限也應受到限制。儘管憑證和金鑰儲存在同一個檔案中,但只有憑證會傳送給用戶端。
可以使用 ssl_protocols 和 ssl_ciphers 指令來限制連線,使其僅包含 SSL/TLS 的強版本和密碼。預設情況下,nginx 使用 "ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3
" 和 "ssl_ciphers HIGH:!aNULL:!MD5
",因此通常不需要明確設定它們。請注意,這些指令的預設值已變更數次。
HTTPS 伺服器最佳化
SSL 操作會消耗額外的 CPU 資源。在多處理器系統上,應執行數個 工作程序,不少於可用 CPU 核心的數量。最消耗 CPU 資源的操作是 SSL 交握。有兩種方法可以最大限度地減少每個用戶端的這些操作次數:第一種是啟用 keepalive 連線,透過一個連線傳送多個請求;第二種是重複使用 SSL 工作階段參數,以避免並行和後續連線的 SSL 交握。工作階段儲存在工作程序之間共用的 SSL 工作階段快取中,並由 ssl_session_cache 指令設定。快取的一個 megabyte 大約包含 4000 個工作階段。預設快取逾時為 5 分鐘。可以使用 ssl_session_timeout 指令增加逾時時間。以下是一個針對具有 10 megabyte 共用工作階段快取的多核心系統進行最佳化的範例設定
worker_processes auto; http { ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; server { listen 443 ssl; server_name www.example.com; keepalive_timeout 70; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ...
SSL 憑證鏈
某些瀏覽器可能會抱怨由知名憑證授權單位簽署的憑證,而其他瀏覽器可能會毫無問題地接受該憑證。發生這種情況的原因是,發證機構使用中繼憑證簽署伺服器憑證,而中繼憑證不存在於特定瀏覽器隨附的知名受信任憑證授權單位憑證庫中。在這種情況下,授權單位會提供一組鏈結憑證,這些憑證應串連到簽署的伺服器憑證。伺服器憑證必須出現在組合檔案中鏈結憑證之前
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt
產生的檔案應在 ssl_certificate 指令中使用
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.chained.crt; ssl_certificate_key www.example.com.key; ... }
如果伺服器憑證和套件串連順序錯誤,nginx 將無法啟動,並顯示錯誤訊息
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed (SSL: error:0B080074:x509 certificate routines: X509_check_private_key:key values mismatch)
因為 nginx 嘗試將私密金鑰與套件的第一個憑證一起使用,而不是伺服器憑證。
瀏覽器通常會儲存它們接收到的、並由受信任的授權單位簽署的中繼憑證,因此,活躍使用的瀏覽器可能已經具有所需的中繼憑證,並且可能不會抱怨在未串連套件的情況下傳送的憑證。為了確保伺服器傳送完整的憑證鏈,可以使用 openssl
命令列公用程式,例如
$ openssl s_client -connect www.godaddy.com:443 ... Certificate chain 0 s:/C=US/ST=Arizona/L=Scottsdale/1.3.6.1.4.1.311.60.2.1.3=US /1.3.6.1.4.1.311.60.2.1.2=AZ/O=GoDaddy.com, Inc /OU=MIS Department/CN=www.GoDaddy.com /serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b) i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc. /OU=http://certificates.godaddy.com/repository /CN=Go Daddy Secure Certification Authority /serialNumber=07969287 1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc. /OU=http://certificates.godaddy.com/repository /CN=Go Daddy Secure Certification Authority /serialNumber=07969287 i:/C=US/O=The Go Daddy Group, Inc. /OU=Go Daddy Class 2 Certification Authority 2 s:/C=US/O=The Go Daddy Group, Inc. /OU=Go Daddy Class 2 Certification Authority i:/L=ValiCert Validation Network/O=ValiCert, Inc. /OU=ValiCert Class 2 Policy Validation Authority /CN=http://www.valicert.com//emailAddress=info@valicert.com ...
在測試使用 SNI 的設定時,請務必指定-servername
選項,因為openssl
預設不使用 SNI。
在此範例中,www.GoDaddy.com
伺服器憑證 #0 的主體(「s」)是由簽署者(「i」)簽署的,而簽署者本身是憑證 #1 的主體,而憑證 #1 是由簽署者簽署的,而簽署者本身是憑證 #2 的主體,而憑證 #2 是由知名發證機構 ValiCert, Inc. 簽署的,其憑證儲存在瀏覽器的內建憑證庫中(即傑克建造的房子裡)。
如果沒有新增憑證套件,則只會顯示伺服器憑證 #0。
單一 HTTP/HTTPS 伺服器
可以設定單一伺服器來處理 HTTP 和 HTTPS 請求
server { listen 80; listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ... }
在 0.7.14 之前,無法如上所示針對個別監聽 sockets 選擇性地啟用 SSL。只能使用 ssl 指令針對整個伺服器啟用 SSL,使得無法設定單一 HTTP/HTTPS 伺服器。listen 指令的 ssl
參數是為了解決此問題而新增的。因此,不建議在現代版本中使用 ssl 指令。
基於名稱的 HTTPS 伺服器
當設定兩個或更多監聽單一 IP 位址的 HTTPS 伺服器時,會出現常見的問題
server { listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ... } server { listen 443 ssl; server_name www.example.org; ssl_certificate www.example.org.crt; ... }
透過此設定,無論請求的伺服器名稱為何,瀏覽器都會收到預設伺服器的憑證,即 www.example.com
。這是由 SSL 通訊協定行為造成的。SSL 連線是在瀏覽器傳送 HTTP 請求之前建立的,而 nginx 並不知道請求的伺服器名稱。因此,它只能提供預設伺服器的憑證。
解決此問題最古老且最穩健的方法是為每個 HTTPS 伺服器指派個別的 IP 位址
server { listen 192.168.1.1:443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ... } server { listen 192.168.1.2:443 ssl; server_name www.example.org; ssl_certificate www.example.org.crt; ... }
具有多個名稱的 SSL 憑證
還有其他方法可以讓數個 HTTPS 伺服器共用單一 IP 位址。但是,它們都有各自的缺點。一種方法是在 SubjectAltName 憑證欄位中使用具有多個名稱的憑證,例如 www.example.com
和 www.example.org
。但是,SubjectAltName 欄位長度有限。
另一種方法是使用具有萬用字元名稱的憑證,例如 *.example.org
。萬用字元憑證會保護指定網域的所有子網域,但只保護一個層級。此憑證符合 www.example.org
,但不符合 example.org
和 www.sub.example.org
。這兩種方法也可以結合使用。憑證可能在 SubjectAltName 欄位中包含精確和萬用字元名稱,例如 example.org
和 *.example.org
。
最好將具有多個名稱的憑證檔案及其私密金鑰檔案放置在組態的 http 層級,以便在所有伺服器中繼承它們的單一記憶體複本
ssl_certificate common.crt; ssl_certificate_key common.key; server { listen 443 ssl; server_name www.example.com; ... } server { listen 443 ssl; server_name www.example.org; ... }
伺服器名稱指示 (Server Name Indication)
在單一 IP 位址上執行數個 HTTPS 伺服器的更通用解決方案是 TLS 伺服器名稱指示擴充功能 (SNI, RFC 6066),它允許瀏覽器在 SSL 交握期間傳遞請求的伺服器名稱,因此,伺服器將知道它應該使用哪個憑證來進行連線。SNI 目前受到大多數現代瀏覽器的支援,儘管某些舊版或特殊用戶端可能不使用 SNI。
只有網域名稱可以在 SNI 中傳遞,但是,如果請求包含常值 IP 位址,某些瀏覽器可能會錯誤地將伺服器的 IP 位址作為其名稱傳遞。不應依賴此方法。
為了在 nginx 中使用 SNI,nginx 二進位檔建置所使用的 OpenSSL 程式庫以及它在執行階段動態連結的程式庫都必須支援 SNI。如果使用 config 選項建置 OpenSSL 0.9.8f 版,則它支援 SNI
$ nginx -V ... TLS SNI support enabled ...
但是,如果啟用 SNI 的 nginx 動態連結到不支援 SNI 的 OpenSSL 程式庫,nginx 會顯示警告
nginx was built with SNI support, however, now it is linked dynamically to an OpenSSL library which has no tlsext support, therefore SNI is not available
相容性
- 自 0.8.21 和 0.7.62 版起,「-V」參數會顯示 SNI 支援狀態。
- listen 指令的
ssl
參數自 0.7.14 版起受到支援。在 0.8.21 版之前,只能與default
參數一起指定。 - 自 0.5.23 版起支援 SNI。
- 自 0.5.6 版起支援共用 SSL 工作階段快取。
- 1.23.4 版及更新版本:預設 SSL 通訊協定為 TLSv1、TLSv1.1、TLSv1.2 和 TLSv1.3(如果 OpenSSL 程式庫支援)。
- 1.9.1 版及更新版本:預設 SSL 通訊協定為 TLSv1、TLSv1.1 和 TLSv1.2(如果 OpenSSL 程式庫支援)。
- 0.7.65、0.8.19 版及更新版本:預設 SSL 通訊協定為 SSLv3、TLSv1、TLSv1.1 和 TLSv1.2(如果 OpenSSL 程式庫支援)。
- 0.7.64、0.8.18 版及更早版本:預設 SSL 通訊協定為 SSLv2、SSLv3 和 TLSv1。
- 1.0.5 版及更新版本:預設 SSL 密碼為 “
HIGH:!aNULL:!MD5
”。 - 0.7.65、0.8.20 版及更新版本:預設 SSL 密碼為 “
HIGH:!ADH:!MD5
”。 - 0.8.19 版:預設 SSL 密碼為 “
ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM
”。 - 0.7.64、0.8.18 版及更早版本:預設 SSL 密碼為
“ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
”。
由 Igor Sysoev 撰寫 由 Brian Mercer 編輯 |