配置HTTPS伺服器

hdgara1發表於2020-06-09

配置HTTPS伺服器

配置HTTPS主機,必須在server配置塊中開啟SSL協議,還需要指定伺服器端證書和金鑰檔案的位置:

server {
listen 443;
server_name
ssl on;
ssl_certificate
ssl_certificate_key
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;

}

伺服器證書是公開的,會被傳送到每一個連線到伺服器的客戶端。而私鑰不是公開的,需要存放在訪問受限的檔案中,當然,nginx主程式必須有讀取金鑰的許可權。私鑰和證書可以存放在同一個檔案中:

ssl_certificate
ssl_certificate_key

這種情況下,證書檔案同樣得設定訪問限制。當然,雖然證書和金鑰存放在同一個檔案,只有證書會傳送給客戶端,金鑰不會傳送。

ssl_protocols和ssl_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
keepalive_timeout 70;

ssl on;
ssl_certificate
ssl_certificate_key
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;

有些瀏覽器不接受那些眾所周知的證書認證機構簽署的證書,而另外一些瀏覽器卻接受它們。這是由於證書籤發使用了一些中間認證機構,這些中間機構被眾所周知的證書認證機構授權代為簽發證書,但是它們自己卻不被廣泛認知,所以有些客戶端不予識別。針對這種情況,證書認證機構提供一個證書鏈的包裹,用來宣告眾所周知的認證機構和自己的關係,需要將這個證書鏈包裹與伺服器證書合併成一個檔案。在這個檔案裡,伺服器證書需要出現在認證方證書鏈的前面:

$ cat bundle.crt >

這個檔案需要使用ssl_certificate指令來引用:

server {
listen 443;
server_name
ssl on;
ssl_certificate ;
ssl_certificate_key

}

如果伺服器證書和認證方證書鏈合併時順序弄錯了,nginx就不能正常啟動,而且會顯示下面的錯誤資訊:

SSL_CTX_use_PrivateKey_file(” … /”) failed
(SSL: error:0B080074:x509 certificate routines:
X509_check_private_key:key values mismatch)

因為nginx首先需要用私鑰去解密伺服器證書,而遇到的卻是認證方的證書。

瀏覽器通常會將那些被受信的認證機構認證的中間認證機構儲存下來,那麼這些瀏覽器以後在遇到使用這些中間認證機構但不包含證書鏈的情況時,因為已經儲存了這些中間認證機構的資訊,所以不會報錯。可以使用openssl命令列工具來確認伺服器傳送了完整的證書鏈:

$ openssl s_client -connect

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=
/serialNumber=0796928-7/2.5.4.15=V1.0, Clause 5.(b)
i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
/OU=
/CN=Go Daddy Secure Certification Authority
/serialNumber=07969287
1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc.
/OU=
/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=

在這個例子中,的伺服器證書(#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
ssl_certificate
ssl_certificate_key

}

在0.8.21版本以前,只有新增了default引數的監聽埠才能新增ssl引數:
listen 443 default ssl;
基於名字的HTTPS主機
如果在同一個IP上配置多個HTTPS主機,會出現一個很普遍的問題:

server {
listen 443;
server_name
ssl on;
ssl_certificate

}

server {
listen 443;
server_name
ssl on;
ssl_certificate

}

使用上面的配置,不論瀏覽器請求哪個主機,都只會收到預設主機的證書。這是由SSL協議本身的行為引起的——先建立SSL連線,再傳送HTTP請求,所以nginx建立SSL連線時不知道所請求主機的名字,因此,它只會返回預設主機的證書。

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

server {
listen 192.168.1.1:443;
server_name
ssl on;
ssl_certificate

}

server {
listen 192.168.1.2:443;
server_name
ssl on;
ssl_certificate

}

帶有多個主機名的SSL證書

也有其他一些方法可以實現多個HTTPS主機共享一個IP地址,但都有不足。其中一種方法是使用在“SubjectAltName”欄位中存放多個名字的證書,比如和。但是,“SubjectAltName”欄位的長度有限制。

另一種方式是使用主機名中含有萬用字元的證書,比如*.example.org。這個證書匹配,但是不匹配example.org和。這兩種方法可以結合在一起——使用在“SubjectAltName”欄位中存放的多個名字的證書,這些名字既可以是確切的名字,也可以是萬用字元,比如example.org和*.example.org。

最好將帶有多個名字的證書和它的金鑰檔案配置在http配置塊中,這樣可以只儲存一份內容複製,所有主機的配置都從中繼承:

ssl_certificate common.crt;
ssl_certificate_key common.key;

server {
listen 443;
server_name
ssl on;

}

server {
listen 443;
server_name
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.65、0.8.19及以後版本,預設SSL協議是SSLv3、TLSv1、TLSc1.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。

全球可信CA機構

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31483669/viewspace-2697035/,如需轉載,請註明出處,否則將追究法律責任。

相關文章