HTTPS伺服器最佳化 SSL憑證鏈 合併HTTP/HTTPS主機 基於名字的HTTPS主機 帶有多個主機名稱的SSL憑證 主機名稱指示 相容性 |
設定HTTPS主機,必須在server設定區塊中開啟SSL協議,還需要指定伺服器端憑證和金鑰檔案的位置:
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主進程必須有讀取金鑰的權限。私鑰和憑證可以存放在同一個檔案中:
ssl_certificate www.example.com.cert;
ssl_certificate_key www.example.com.cert;
這種情況下,憑證檔案同樣得設定存取限制。當然,雖然證書和密鑰存放在同一個文件,只有證書會發送給客戶端,密鑰不會發送。
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握手的操作。個會話。有些瀏覽器不接受那些眾所周知的證書認證機構簽署的證書,而另一些瀏覽器卻接受它們。但是它們本身卻不被廣泛認知,所以有些客戶端不予識別。包裹與伺服器憑證合併成一個檔案。方證書鏈合併時順序弄錯了,nginx就不能正常啟動,而且會顯示下面的錯誤訊息:
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;
...
因為nginx首先需要用私鑰去解密伺服器證書,而遇到的卻是認證方的憑證。中間認證機構的訊息,所以不會報錯。可以使用openssl
命令列工具來確認伺服器發送了完整的憑證鏈:
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt
在這個範例中,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 443;
server_name www.example.com;
ssl on;
ssl_certificate www.example.com.chained.crt;
ssl_certificate_key www.example.com.key;
...
}
在0.8.21版本以前,只有新增了
default在0.8.21版本以前,只有新增了default
參數的監聽埠才能加入參數:
SSL_CTX_use_PrivateKey_file(" ... /www.example.com.key") failed
(SSL: error:0B080074:x509 certificate routines:
X509_check_private_key:key values mismatch)
基於名字的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.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;
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.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
。
作者: Igor Sysoev 编辑: Brian Mercer 翻译: cfsego |
以上就介绍了nginx 配置HTTPS服务器,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。