SSL配置
一、配置https服务器
配置https服务器,在nginx.conf文件的 listen 指令中需加上 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; ssl_ciphers HIGH:!aNULL:!MD5; #... }
服务器证书是公共实体。它被发送到连接到NGINX或NGINX Plus服务器的每个客户端。私钥是一个安全实体,应存储在具有受限访问权限的文件中,且nginx主程序可以读取此文件。另外,私钥可以与公共证书存储在同一文件中:
ssl_certificate www.example.com.cert;
ssl_certificate_key www.example.com.cert;
在这种情况下,限制对文件的访问非常重要。请注意,尽管在这种情况下证书和密钥存储在一个文件中,但是仅证书被发送到客户端。
ssl_protocols和ssl_ciphers指令可用于要求客户端在建立连接时仅使用SSL / TLS的强版本和密码。
有时在较旧的密码设计中会发现漏洞,建议您在现代NGINX配置中将其禁用(遗憾的是,由于现有NGINX部署的向后兼容性,默认配置无法轻易更改)。请注意,CBC模式密码可能容易受到多种攻击(尤其是BEAST攻击,如CVE-2011-3389中所述),并且由于POODLE攻击,我们建议不要使用SSLv3,除非您需要支持旧版客户端。
二、HTTPS优化
SSL操作会消耗额外的CPU资源。最耗CPU的操作是SSL握手。有两种方法可以最大程度地减少每个客户端执行这些操作的次数:
- 启用保持连接以通过一个连接发送多个请求
- 重用SSL会话参数以避免并行和后续连接的SSL握手
session存储在工作进程之间共享的SSL会话缓存中,并由ssl_session_cache指令进行配置。1 MB的缓存可存储大约4000个会话。默认的缓存超时为5分钟。可以使用ssl_session_timeout指令来增加此超时时间。以下是针对具有10 MB共享会话缓存的多核系统进行优化的示例配置:
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会启动失败并抛出错误信息。
为了确保服务器发送完整的证书链,可以使用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的主题由发卡行(i)签名,发卡行本身就是证书#1的主体。
但是,此证书由著名的发行商ValiCert,Inc.签名,其证书存储在浏览器中。如果尚未添加证书捆绑包,则仅显示服务器证书(#0)。
四、单一的HTTP/HTTPS服务器:
通过配置多个listen指令,可以配置一个同时处理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; #... }
五、基于名称的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协议本身的行为引起的。在浏览器发送HTTP请求之前,已建立SSL连接,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; #... }
请注意,HTTPS上游还有一些特定的代理设置(proxy_ssl_ciphers,proxy_ssl_protocols和proxy_ssl_session_reuse),可用于在NGINX和上游服务器之间微调SSL。
五、多域名的数字证书
如果使用一个IP地址建立多个HTTPS服务器,也有其他的方法。虽然这些方法也有其缺点。其中一种方法就是在SubjectAltName证书字段中使用具有多个域名名称的证书,比如该字段含有:www.example.com
and www.example.org。虽然如此,其字段长度是有限制的。
还有一种方法就是使用泛域名证书,比如:*.example.org。泛域名对指定域名的所有子域名都具有安全性,但仅限于一级。该证书匹配www.example.org,但不匹配 example.org 或者 www.sub.example.org。
以上两种方法可以组合使用,一个证书在 SubjectAltName 字段中可以包含确切的和泛域名。比如:example.org 和 *.example.org。
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; #... }
上面的例子将证书放在http层级中,以便让所有http服务器继承。
六、SNI 服务器名称指示
使用单一IP运行多个HTTPS服务器,还有个做法就是用TLS服务器名称指示(SNI),它能让浏览器在SSL握手期间传递服务器域名,服务器能获使用哪种证书认证。但是,SNI仅被某些浏览器支持:
- Opera 8.0
- MSIE 7.0 (Windows Vista或更高版本)
- Firefox 2.0 和使用Mozilla框架rv:1.8.1的浏览器
- Safari 3.2.1 (Windows Vista或更高版本)
- Chrome (Windows Vista或更高版本)
SNI仅仅将域名传递出去,但有些服务哭喊会将IP地址当作其名称传递了。
要检查nginx是否支持SNI,可以在命令中加上-V参数:
$ nginx -V
...
TLS SNI support enabled
...
七、兼容性
nginx 0.7.14版本开始支持 listen 指令添加 ssl 参数,0.8.21先前版本只支持 default 参数;
1.9.1和后续版本:SSL协议默认有TLSv1
, TLSv1.1
, and TLSv1.2;
0.7.65和0.8.19及后续版本:SSL协议默认有SSLv3
, TLSv1
, TLSv1.1
, 和 TLSv1.2;
1.05和后续版本:SSL ciphers 默认为 HIGH:!aNULL:!MD5;