Nginx:配置HTTPS 服務器

sqor9440 7年前發布 | 38K 次閱讀 SSL協議 Nginx Web服務器 HTTPS

要配置HTTPS NGINX 服務器,必須在配置文件 server 塊中的監聽指令 listen 后啟用 ssl 參數,并且指定服務器證書 ssl_certificate 和私鑰 ssl_certificate_key 的位置:

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;
    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”版本和“ssl_ciphers HIGH:!aNULL:!MD5”密碼,因此通常不需要顯式地配置它們。 注意,這些指令的默認值已經 變更 好幾次了。

HTTPS 服務器優化

SSL操作會消耗額外的CPU資源。 在多處理器系統上,應該運行不少于可用CPU內核數的多個 工作進程 。最耗CPU的操作是SSL握手。有兩種方法來最小化每個客戶端執行這些操作的次數:第一是通過啟用 keepalive_timeout 參數來讓這些連接在一個連接中發送多個請求,第二是重用SSL會話參數,以避免并行和后續連接的SSL握手。這些會話存儲在NGINX工作程序的共享SSL會話緩存中,并由 ssl_session_cache 指令配置。 1M的高速緩存包含大約4000個會話。默認的緩存超時時間為5分鐘。它可以通過使用 ssl_session_timeout 指令增大。 下面是針對具有10M共享緩存的多核心系統的優化示例配置:

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;
        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_s_
   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
...

在本示例中, www.GoDaddy.com 證書鏈中的 #0 號證書的證書請求者("s")由簽發者("i")簽發,而簽發者("i")本身又是 #1 號證書的請求者("s"),它的證書簽發者是 #2 號證書的請求者,它請求的證書由知名發布者 ValiCert,Inc. 簽發,其證書存儲在瀏覽器的內置證書庫中(如同英國童謠 The House That Jack Built 講述的一樣)。

如果捆綁證書沒有被添加到證書鏈,那只有 #0 號證書會被展示出來。

### 單個 HTTP/HTTPS 虛擬主機

現在,在單個nginx虛擬主上可以配置同時處理 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之前的版本無法向上面那樣為單個偵聽套接字選擇性啟用SSL,而只能使用 ssl 指令為整個服務器啟用SSL,從而無法設置單個HTTP / HTTPS虛擬主機服務器,所以在 listen 指令后增加了 ssl 參數來解決此問題。因此不建議在現代版本中使用 ssl 這個指令。

### 基于名稱的 HTTPS 服務器

當配置兩個或多個HTTPS虛擬主機服務器偵聽單個IP地址時會出現常見問題:

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 。

It is better to place a certificate file with several names and its private key file at the http level of configuration to inherit their single memory copy in all servers: 最好在配置文件的 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;
    ...
}

### 服務器名稱指示

單個IP地址上運行多個HTTPS虛擬服務器的更通用的解決方案是 TLS服務器名稱指示擴展 (SNI,RFC 6066),其允許瀏覽器在SSL握手期間同時發送請求的服務器名稱,因此,服務器就知道它應該給這個連接使用哪個證書。然而,SNI限制了它支持的瀏覽器。 目前支持從以下瀏覽器版本及其后:

  • Opera 8.0;
  • IE 7.0 (Windows Vista及更高版本);
  • Firefox 2.0 及其他使用 Mozilla Platform rv:1.8.1 的瀏覽器;
  • Safari 3.2.1 (Windows版本支持Windows Vista及更高版本);
  • Chrome (Windows版本支持Windows Vista及更高版本).

只有域名可以在SNI中傳遞,然而如果請求包含IP地址,一些瀏覽器可能錯誤地把服務器的IP地址作為其名稱進行傳遞,我們不能依賴于這個。

為了在nginx中使用SNI,必須在構建nginx的OpenSSL庫以及運行時的動態鏈接庫中支持它。OpenSSL從0.9.8f版本支持SNI,如果在編譯時給 config 增加了 --enable-tlsext 選項;從OpenSSL 0.9.8j版本開始默認啟用此選項。如果nginx是以支持SNI方式構建的,當使用“-V”參數運行時,nginx會顯示這一信息:

$ 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支持狀態;
  • 從 0.7.14 版本開始支持 listen 指令的 ssl 參數;更早版本到 0.8.21 只能使用'default'參數指定;
  • 從 0.5.23 版本開始支持SNI;
  • 從 0.5.6 版本開始支持共享SSL會話緩存;
  • 從 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, and 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 翻譯人員:nobodybutyou

 

來自:http://www.zcfy.cc/article/nginx-configuring-https-servers-2278.html

 

 本文由用戶 sqor9440 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!