首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Configuring HTTPS servers

  • HTTPS服务器优化
  • SSL证书链
  • 一个HTTP / HTTPS服务器
  • 基于名称的HTTPS服务器
  • 具有多个名称的SSL证书
  • 服务器名称指示
  • 兼容性

要配置HTTPS服务器,ssl必须在服务器块的侦听套接字上启用参数,并且应指定服务器证书和私钥文件的位置:

代码语言:javascript
复制
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的主进程读取。私钥也可以存储在与证书相同的文件中:

代码语言:javascript
复制
    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握手进行并行连接和后续连接。会话存储在工作人员共享的SSL会话缓存中,并由ssl_session_cache指令进行配置。一兆字节的缓存包含约4000个会话。默认缓存超时时间为5分钟。它可以通过使用ssl_session_timeout指令来增加。

代码语言:javascript
复制
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证书链

某些浏览器可能会抱怨由知名证书颁发机构签署的证书,而其他浏览器可能会接受证书而没有问题。发生这种情况的原因是,颁发机构使用中间证书对服务器证书进行了签名,该中间证书不在与特定浏览器一起分发的众所周知的受信任证书颁发机构的证书库中。在这种情况下,权威机构提供一系列链接的证书,这些证书应连接到已签署的服务器证书。服务器证书必须出现在组合文件中的链接证书之前:

代码语言:javascript
复制
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt

生成的文件应该在ssl_certificate指令中使用:

代码语言:javascript
复制
server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

如果服务器证书和软件包已按照错误顺序连接,nginx将无法启动并显示错误消息:

代码语言:javascript
复制
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可以使用命令行实用程序,例如:

代码语言:javascript
复制
$ 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。

在这个例子中,服务器证书#0 的主题(“ s ”)www.GoDaddy.com由发行者(“ i ”)签署,发行者本身是证书#1的主体,由发行者签署,发行者本身是证书#2,由知名发行人ValiCert,Inc.签署,证书存储在浏览器内置的证书库(位于Jack生产的房屋内)。

如果尚未添加证书包,则只显示服务器证书#0。

一个HTTP / HTTPS服务器

可以配置同时处理HTTP和HTTPS请求的单个服务器:

代码语言:javascript
复制
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服务器。ssllisten指令的参数被添加来解决这个问题。现代版本中ssl指令的使用因此而受到阻碍。

基于名称的HTTPS服务器

在配置监听单个IP地址的两个或多个HTTPS服务器时出现常见问题:

代码语言:javascript
复制
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协议行为造成的。 SSL连接在浏览器发送HTTP请求之前建立,而nginx不知道请求的服务器的名称。 因此,它可能只提供默认服务器的证书。

解决该问题的最老且最稳健的方法是为每个HTTPS服务器分配一个单独的IP地址:

代码语言:javascript
复制
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.comwww.example.org。但是,SubjectAltName字段的长度是有限的。

另一种方法是使用带有通配符名称的证书,例如*.example.org。通配符证书可以保护指定域的所有子域,但仅限于一个级别。该证书相匹配www.example.org,但不匹配example.orgwww.sub.example.org。这两种方法也可以结合使用。例如,example.org和证书中,证书可能在SubjectAltName字段中包含确切名称和通配符名称*.example.org

最好在配置的http 级别放置一个带有多个名称及其私钥文件的证书文件,以在所有服务器中继承其单个内存副本:

代码语言:javascript
复制
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;
    ...
}

服务器名称指示

在单个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支持构建的,那么nginx会在使用“-V”开关运行时显示:

代码语言:javascript
复制
$ nginx -V
...
TLS SNI support enabled
...

但是,如果启用SNI的nginx动态链接到没有SNI支持的OpenSSL库,nginx会显示以下警告:

代码语言:javascript
复制
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支持状态。
  • listen指令的ssl参数从0.7.14开始支持。 在0.8.21之前,它只能与默认参数一起指定。
  • 自0.5.23以来,SNI一直得到支持。
  • 自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”.

| 由Brian Mercer编辑的Igor |

|:----|

扫码关注腾讯云开发者

领取腾讯云代金券