默认配置
要配置HTTPS服务器,必须 在服务器块中的侦听套接字上启用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的主进程可读的。私钥可以替代地存储在与证书相同的文件中:
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 连接来通过一个连接发送多个请求,第二种方法是重用SSL会话参数以避免SSL并行连接和后续连接。会话存储在worker之间共享的SSL会话高速缓存中,并由ssl_session_cache 指令配置 。一兆字节的缓存包含大约4000个会话。默认缓存超时为5分钟。它可以通过使用增加 ssl_session_timeout 指令。以下是针对具有10兆字节共享会话缓存的多核系统优化的示例配置:
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;
...
}
如果服务器证书和软件包的连接(cat bundle.crt > chained.crt )顺序错误,则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尝试将私钥与bundle的第一个证书而不是服务器证书一起使用。
浏览器通常存储他们收到的中间证书,并由受信任的权威机构签名,因此主动使用的浏览器可能已经拥有所需的中间证书,并且可能不会警告没有证书链发送的证书。要确保服务器发送完整的证书链,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
...
使用SNI测试配置时,指定-servername选项非常重要,因为openssl默认情况下不使用SNI。
In this example the subject (“s”) of the www.GoDaddy.com server certificate #0 is signed by an issuer (“i”) which itself is the subject of the certificate #1, which is signed by an issuer which itself is the subject of the certificate #2, which signed by the well-known issuer ValiCert, Inc. whose certificate is stored in the browsers’ built-in certificate base (that lay in the house that Jack built).
在该示例中,服务器证书#0 的主题(“ s ”) www.GoDaddy.com由发行者(“ i ”)签名,发行者本身是证书#1的主题,其由发行者签署,发行者本身是发行者的主题。证书#2,由知名发行人ValiCert,Inc。签署, 其证书存储在浏览器的内置证书库(位于Jack建造的房屋内)中。
如果尚未添加证书包,则仅显示服务器证书#0。
单个HTTP / HTTPS服务器
可以配置处理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服务器。添加ssl了listen指令的参数 来解决此问题。因此不鼓励在现代版本中使用 ssl指令。
基于名称的HTTPS服务器
配置侦听单个IP地址的两个或多个HTTPS服务器时会出现一个常见问题:
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;
...
}
具有多个名称的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 ssl;
server_name www.example.com;
...
}
server {
listen 443 ssl;
server_name www.example.org;
...
}
服务器名称指示(SNI)
在单个IP地址上运行多个HTTPS服务器的更通用的解决方案是 TLS服务器名称指示扩展(SNI,RFC 6066),它允许浏览器在SSL握手期间传递请求的服务器名称,因此,服务器将知道哪个它应该用于连接的证书。目前 大多数现代浏览器都支持 SNI ,但某些老浏览器或特殊浏览器可能无法使用。
只有域名可以在SNI中传递,但是如果请求包含文字IP地址,某些浏览器可能会错误地将服务器的IP地址作为其名称传递。人们不应该依赖于此。
为了在nginx中使用SNI,必须在构建nginx二进制文件的OpenSSL库以及在运行时动态链接到的库中支持它。如果使用配置选项“--enable-tlsext”构建,OpenSSL支持0.9.8f版本的SNI 。 自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一起指定 。
SNI自0.5.23以来一直受到支持。
自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和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”。
网友评论