nginx 學習筆記(9) 配置HTTPS服務器--轉載

HTTPS服務器優化
SSL證書鏈
合併HTTP/HTTPS主機
基於名字的HTTPS主機
帶有多個主機名的SSL證書
主機名指示
兼容性

配置HTTPS主機,必須在server配置塊中打開SSL協議,還須要指定服務器端證書和密鑰文件的位置:html

server {
    listen              443;
    server_name         www.example.com;
    ssl                 on;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ...
}

服務器證書是公開的,會被傳送到每個鏈接到服務器的客戶端。而私鑰不是公開的,須要存放在訪問受限的文件中,固然,nginx主進程必須有讀取密鑰的權限。私鑰和證書能夠存放在同一個文件中:nginx

    ssl_certificate     www.example.com.cert;
    ssl_certificate_key www.example.com.cert;

這種狀況下,證書文件一樣得設置訪問限制。固然,雖然證書和密鑰存放在同一個文件,只有證書會發送給客戶端,密鑰不會發送。web

ssl_protocolsssl_ciphers指令能夠用來強制用戶鏈接只能引入SSL/TLS那些強壯的協議版本和強大的加密算法。從1.0.5版本開始,nginx默認使用「ssl_protocols SSLv3 TLSv1」和「ssl_ciphers HIGH:!aNULL:!MD5」,因此只有在以前的版本,明確地配置它們纔是有意義的。從1.1.13和1.0.12版本開始,nginx默認使用「ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2」。算法

CBC模式的加密算法容易受到一些攻擊,尤爲是BEAST攻擊(參見CVE-2011-3389)。能夠經過下面配置調整爲優先使用RC4-SHA加密算法:瀏覽器

    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

HTTPS服務器優化

SSL操做須要消耗CPU資源,因此在多處理器的系統,須要啓動多個工做進程,並且數量須要很多於可用CPU的個數。最消耗CPU資源的SSL操做是SSL握手,有兩種方法能夠將每一個客戶端的握手操做數量降到最低:第一種是保持客戶端長鏈接,在一個SSL鏈接發送多個請求,第二種是在併發的鏈接或者後續的鏈接中重用SSL會話參數,這樣能夠避免SSL握手的操做。會話緩存用於保存SSL會話,這些緩存在工做進程間共享,可使用ssl_session_cache指令進行配置。1M緩存能夠存放大約4000個會話。默認的緩存超時是5分鐘,可使用ssl_session_timeout加大它。下面是一個針對4核系統的配置優化的例子,使用10M的共享會話緩存:緩存

worker_processes  4;

http {
    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;

    server {
        listen              443;
        server_name         www.example.com;
        keepalive_timeout   70;

        ssl                 on;
        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       SSLv3 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指令來引用:session

server {
    listen              443;
    server_name         www.example.com;
    ssl                 on;
    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
...

在這個例子中,www.GoDaddy.com的服務器證書(#0)的受籤者(「s」)是被簽發機構(「i」)簽名的,而這個簽發機構又是證書(#1)的受籤者,接着證書(#1)的簽發機構又是證書(#2)的受籤者,最後證書(#2)是被衆所周知的簽發機構ValiCert, Inc簽發。ValiCert, Inc的證書內嵌在瀏覽器中,被瀏覽器自動識別(這段話神似英國詩《在Jack蓋的房子裏》裏面的內容)。

若是沒有加入認證方證書鏈,就只會顯示服務器證書(#0)。

合併HTTP/HTTPS主機

若是HTTP和HTTPS虛擬主機的功能是一致的,能夠配置一個虛擬主機,既處理HTTP請求,又處理HTTPS請求。 配置的方法是刪除ssl on的指令,並在*:443端口添加參數ssl

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.8.21版本之前,只有添加了 default參數的監聽端口才能添加 ssl參數:
listen  443  default ssl;

基於名字的HTTPS主機

若是在同一個IP上配置多個HTTPS主機,會出現一個很廣泛的問題:

server {
    listen          443;
    server_name     www.example.com;
    ssl             on;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          443;
    server_name     www.example.org;
    ssl             on;
    ssl_certificate www.example.org.crt;
    ...
}

使用上面的配置,不論瀏覽器請求哪一個主機,都只會收到默認主機www.example.com的證書。這是由SSL協議自己的行爲引發的——先創建SSL鏈接,再發送HTTP請求,因此nginx創建SSL鏈接時不知道所請求主機的名字,所以,它只會返回默認主機的證書。

最古老的也是最穩定的解決方法就是每一個HTTPS主機使用不一樣的IP地址:

server {
    listen          192.168.1.1:443;
    server_name     www.example.com;
    ssl             on;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443;
    server_name     www.example.org;
    ssl             on;
    ssl_certificate www.example.org.crt;
    ...
}

帶有多個主機名的SSL證書

也有其餘一些方法能夠實現多個HTTPS主機共享一個IP地址,但都有不足。其中一種方法是使用在「SubjectAltName」字段中存放多個名字的證書,好比www.example.comwww.example.org。可是,「SubjectAltName」字段的長度有限制。

另外一種方式是使用主機名中含有通配符的證書,好比*.example.org。這個證書匹配www.example.org,可是不匹配example.orgwww.sub.example.org。這兩種方法能夠結合在一塊兒——使用在「SubjectAltName」字段中存放的多個名字的證書,這些名字既能夠是確切的名字,也能夠是通配符,好比example.org*.example.org

最好將帶有多個名字的證書和它的密鑰文件配置在http配置塊中,這樣能夠只保存一分內容拷貝,全部主機的配置都從中繼承:

ssl_certificate      common.crt;
ssl_certificate_key  common.key;

server {
    listen          443;
    server_name     www.example.com;
    ssl             on;
    ...
}

server {
    listen          443;
    server_name     www.example.org;
    ssl             on;
    ...
}

主機名指示

在一個IP上運行多個HTTPS主機的更通用的方案是TLS主機名指示擴展(SNI,RFC6066),它容許瀏覽器和服務器進行SSL握手時,將請求的主機名傳遞給服務器,所以服務器能夠知道使用哪個證書來服務這個鏈接。但SNI只獲得有限的瀏覽器的支持。下面列舉支持SNI的瀏覽器最低版本和平臺信息:

  • Opera 8.0;
  • MSIE 7.0(僅在Windows Vista操做系統及後續操做系統);
  • Firefox 2.0和使用Mozilla平臺1.8.1版本的其餘瀏覽器;
  • Safari 3.2.1(Windows版須要最低Vista操做系統);
  • Chrome(Windows版須要最低Vista操做系統)。
經過SNI只能傳遞域名,可是,當請求中包含可讀的IP地址時,某些瀏覽器將服務器的IP地址做爲服務器的名字進行了傳送。這是一個錯誤,你們不該該依賴於這個。

爲了在nginx中使用SNI,那麼不管是在編譯nginx時使用的OpenSSL類庫,仍是在運行nginx時使用的OpenSSL運行庫,都必須支持SNI。從0.9.8f版本開始,OpenSSL經過「--enable-tlsext」配置選項加入SNI支持,從0.9.8j版本開始,此選項成爲默認選項。當nginx被編譯成支持SNI時,在使用「-V」選項運行時會顯示以下信息:

$ 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」選項運行nginx時,將顯示SNI支持狀態信息。
  • 從0.7.14版本開始,listen指令支持ssl參數。
  • 從0.5.32版本開始,支持SNI。
  • 從0.5.6版本開始,支持SSL會話緩存,並可在工做進程間共享。
  • 0.7.6五、0.8.19及之後版本,默認SSL協議是SSLv三、TLSv一、TLSc1.1和TLSv1.2(若是OpenSSL庫支持)。
  • 0.7.6四、0.8.18及之前版本,默認SSL協議是SSLv二、SSLv3和TLSv1。
  • 1.0.5及之後版本,默認SSL密碼算法是HIGH:!aNULL:!MD5
  • 0.7.6五、0.8.20及之後版本,默認SSL密碼算法是HIGH:!ADH:!MD5
  • 0.8.19版本,默認SSL密碼算法是ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM
  • 0.7.6四、0.8.18及之前版本,默認SSL密碼算法是ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP

做者: Igor Sysoev編輯: Brian Mercer翻譯: cfsego
相關文章
相關標籤/搜索