1    设置HTTPS服务器

为了设置HTTPS服务器,可以在nginx.conf文件中为server块中的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的主进程必须能够读取该文件。秘钥和证书存储在相同的文件中:

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

在这种情况下,文件访问权限应该是严格的。虽然证书和键存储在一个文件中,但只有证书会发送到客户端。

ssl_protocolsssl_ciphers指令可以用于限制只有包含强版本和加密的SSL/TLS的连接可以访问。

从1.0.5开始,NGINX默认使用ssl_protocols SSLv3 TLSv1ssl_ciphers HIGH:!aNULL:MD5;从1.1.13和1.0.12开始,默认更新到ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2

有时会在老的密码设计中找到漏洞,最好在现代NGINX配置中禁用(可惜,默认配置不易改变,因为要向后兼容)。请注意,CBC模式密码可能会受到大量攻击,尤其是BEAST攻击,由于POODLE攻击,最好避免使用SSLv3,除非你需要支持遗留客户端。



2    HTTPS服务器优化

SSL操作消耗额外的CPU资源。大多数CPU密集操作是SSL握手。有两种方式可以减少每个客户端的这些操作数:

  • 启用keepalive连接,通过一个连接发送多个请求。
  • 重用SSL会话参数,避免并行和后续连接的SSL握手。

会话存储在SSL会话缓存中,在worker进程之间共享,通过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;
        # ...
    }
}



3    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将启动失败并显示以下错误消息:

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

...



4    单个HTTP/HTTPS服务器

可以配置单个服务器处理HTTP和HTTPS请求,在相同的虚拟主机中,使用一个带有ssl参数和一个没有ssl参数的listen:

server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    # ...
}

在NGINX 0.7.13和更早版本中,SSL不能选择性的启用监听套接字。只能使用ssl指令启用整个服务器的SSL,让它不能设置一个HTTP/HTTPS服务器。listen指令的ssl参数解决了这个问题。



5    基于名称的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不知道请求的服务器名称。因此,它可能只提供默认的服务器证书。

最好的方式是分配不同的IP地址给每个HTTPS服务器:

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;
    # ...
}



5.1    一个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;
    # ...
}