1. 博客/

nginx tls版本配置

·1047 字·5 分钟
Nginx

问题
#

nginx配置多个ssl虚拟主机,虚拟机配置不同ssl_protocols时,表现不符合预期

示例
#

先看一个nginx配置示例,ssl配置参考 SSL Configuration Generator

[root@test-1 conf.d]# pwd
/usr/local/openresty/nginx/conf/conf.d
[root@test-1 conf.d]# ls
a.ffu.com.conf  b.ffu.com.conf  c.ffu.com.conf
[root@test-1 conf.d]# cat a.ffu.com.conf
server {
        listen       443 ssl;
        server_name  a.ffu.com;

        ssl_certificate             ssl/server.crt;
        ssl_certificate_key         ssl/server.key;
        ssl_session_timeout         5m;
	      ssl_protocols               TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
        ssl_prefer_server_ciphers   on;
        location / {
           root html;
           index  index.html index.htm;
	}
}
[root@test-1 conf.d]# cat b.ffu.com.conf
server {
        listen       443 ssl;
        server_name  b.ffu.com;

        ssl_certificate             ssl/server.crt;
        ssl_certificate_key         ssl/server.key;
        ssl_session_timeout         5m;
        ssl_protocols               TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA;
        ssl_prefer_server_ciphers   on;
        location / {
           root html;
           index  index.html index.htm;
	}
}

客户端验证
#

客户端请求验证server支持的TLS版本

虚拟主机a.ffu.com
#

不支持TLSv1和TLSv1.1,和配置一致ssl_protocols TLSv1.2 TLSv1.3;

[root@localhost] ~$ openssl s_client -servername a.ffu.com -connect a.ffu.com:443 -tls1 < /dev/null
CONNECTED(00000003)
140616533698448:error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version:s3_pkt.c:1493:SSL alert number 70
140616533698448:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:659:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1718960402
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---
[root@localhost] ~$ openssl s_client -servername a.ffu.com -connect a.ffu.com:443 -tls1_1 < /dev/null
CONNECTED(00000003)
140378553411472:error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version:s3_pkt.c:1493:SSL alert number 70
140378553411472:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:659:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.1
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1718960405
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

[root@localhost] ~$ openssl s_client -servername a.ffu.com -connect a.ffu.com:443 -tls1_2 -no_ticket  < /dev/null
CONNECTED(00000003)
depth=0 CN = *.ffu.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = *.ffu.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/CN=*.ffu.com
   i:/CN=FFU ROOT CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDAzCCAeugAwIBAgIBAjANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtGRlUg
Uk9PVCBDQTAeFw0yNDA1MTcwNjM5MjRaFw0yNTA1MTcwNjM5MjRaMBQxEjAQBgNV
BAMMCSouZmZ1LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMuq
+ke4/mfaXMFMAj7u9VHhumC3UBJCQ6j60Vd2LUMX+lQqNfoHiIRPfYBjSt/hEnmr
ePDnMvtimqTOTjPpCajiRiaKtLQrhtOB3QhXllibF2P5b1shF0ed6n+yr52f9JOF
mc6H3skFuFNsAtp4GuuUoUPp5Nqjv643/FWO7mfOPbrcqPbl7PhcenowAClk5ZzY
jGWTJC3EaM+C4bmburNS8QUnsk0O6MxjGw6jhaRROVMhLfsMoOJTZzmU5Ff4qjOP
mp+hnIF+1dEA5vBiWncZxffEGd55U1JdjysXInvxjg8VP28ItcRY7V6ad1DrakE7
oSjGtyeXpCy9RP9vzDsCAwEAAaNeMFwwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCMGA1UdEQQcMBqCCSouZmZ1
LmNvbYIHZmZ1LmNvbYcEClkJgTANBgkqhkiG9w0BAQsFAAOCAQEAcNQL4pA7xGrw
DoknuV+jx9FEdHAyS6gTdzWHz4Fz1FA5qSY2FL7wpH4CQDPyCYhezOPtjpK6cvAd
cOj251M5ZyafRP+ZWOz9bDl3hOCwHnhsHiyB2WrUCOQILpw/m2dapuflDfzUs92h
gCbOCA9bX9AiG09gLHaPYvkF+eNRLUtDZ39xOGQz2lf/fj1OtQDXz2OkGcCny5Ip
U7ESIoEY0loREsB2D7caugwuTOGZusWuzX9D9//dZhyacETzsJBE//RxI2df5INB
krmYjklWiWN9TE5ZOh0l7anQCasOegpymmKXCzViYxFCFwFiHNIHLwQ0YBcIUWUb
pXWyUr/FGw==
-----END CERTIFICATE-----
subject=/CN=*.ffu.com
issuer=/CN=FFU ROOT CA
---
No client certificate CA names sent
Peer signing digest: SHA256
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 1286 bytes and written 429 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Sesson-ID: 49BC497A0318A94CA554137F655121CB3421E06292626E9CFAF372096AB5DF0A
    Session-ID-ctx:
    Master-Key: 32FF67B7B1C51670D707D3D623D0063917458EE5AA6941E8F9ECC6BC723DA5C6162E0835CB4AF7FFE2E21FB3F9F22DE7
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1718960895
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---
DONE

虚拟主机b.ffu.com
#

不支持TLSv1和TLSv1.1,和配置不一致ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;

[root@localhost] ~$ curl -kvI  --tlsv1.0 https://b.ffu.com
* About to connect() to b.ffu.com port 443 (#0)
*   Trying 10.89.9.129...
* Connected to b.ffu.com (10.89.9.129) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* NSS error -12190 (SSL_ERROR_PROTOCOL_VERSION_ALERT)
* Peer reports incompatible or unsupported protocol version.
* Closing connection 0
curl: (35) Peer reports incompatible or unsupported protocol version.

[root@localhost] ~$ curl -kvI  --tlsv1.1 https://b.ffu.com
* About to connect() to b.ffu.com port 443 (#0)
*   Trying 10.89.9.129...
* Connected to b.ffu.com (10.89.9.129) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* NSS error -12190 (SSL_ERROR_PROTOCOL_VERSION_ALERT)
* Peer reports incompatible or unsupported protocol version.
* Closing connection 0
curl: (35) Peer reports incompatible or unsupported protocol version.
[root@localhost] ~$ curl -kvI  --tlsv1.2 https://b.ffu.com
* About to connect() to b.ffu.com port 443 (#0)
*   Trying 10.89.9.129...
* Connected to b.ffu.com (10.89.9.129) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* 	subject: CN=*.ffu.com
* 	start date: 5月 17 06:39:24 2024 GMT
* 	expire date: 5月 17 06:39:24 2025 GMT
* 	common name: *.ffu.com
* 	issuer: CN=FFU ROOT CA
> HEAD / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: b.ffu.com
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: openresty
Server: openresty
< Date: Fri, 21 May 2024 09:16:16 GMT
Date: Fri, 21 May 2024 09:16:16 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 1097
Content-Length: 1097
< Last-Modified: Fri, 06 Nov 2020 08:26:32 GMT
Last-Modified: Fri, 06 Nov 2020 08:26:32 GMT
< Connection: keep-alive
Connection: keep-alive
< Vary: Accept-Encoding
Vary: Accept-Encoding
< ETag: "5fa508b8-449"
ETag: "5fa508b8-449"
< Accept-Ranges: bytes
Accept-Ranges: bytes

<
* Connection #0 to host b.ffu.com left intact

为什么虚拟主机配置文件b.ffu.com.conf中ssl_protocols指定了TLSv1 TLSv1.1 还不支持呢?官方文档解释 ssl_protocols应该在default server中配置

in case of the ssl_protocols directive, the protocol list is set by the OpenSSL library before the server configuration could be applied according to the name requested through SNI, thus, protocols should be specified only for a default server;

nginx default server的指定方式

server {
    listen      80 default_server;
    server_name example.net www.example.net;
    ...
}

如果没有显式指定,那么第一个虚拟主机配置就是default server

In the configuration above, the default server is the first one — which is nginx’s standard default behaviour. It can also be set explicitly which server should be default, with the default_server parameter in the listen directive:

查看上面示例中nginx加载配置顺序,第一个有效配置文件是a.ffu.com.conf,所以几个域名ssl_protocols只支持TLSv1.2和TLSv1.3

[root@test-1 conf.d]# openresty -T|grep '# configuration'
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful
# configuration file /usr/local/openresty/nginx/conf/nginx.conf:
# configuration file /usr/local/openresty/nginx/conf/mime.types:
# configuration file /usr/local/openresty/nginx/conf/conf.d/a.ffu.com.conf:
# configuration file /usr/local/openresty/nginx/conf/conf.d/b.ffu.com.conf:
# configuration file /usr/local/openresty/nginx/conf/conf.d/c.ffu.com.conf:
# configuration file /usr/local/openresty/nginx/conf/stream.d/stream.conf:

配置default_server
#

创建default.conf指定default_server

[root@test-1 conf.d]# cat defult.conf
server {
        listen       443 ssl default_server;
        server_name  _;

        ssl_certificate             ssl/server.crt;
        ssl_certificate_key         ssl/server.key;
        ssl_session_timeout         5m;
        ssl_protocols               TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA;
        ssl_prefer_server_ciphers   on;
        location / {
           root html;
           index  index.html index.htm;
	}
}

客户端再次验证
#

a.ffu.com支持TLSv1版本,但是指定的tls密码套件ssl_ciphers不支持,所以加密算法协商失败,返回错误SSL_ERROR_NO_CYPHER_OVERLAP

b.ffu.com支持TLSv1版本,请求正常

[root@localhost] ~$ curl -kvI  --tlsv1.0 https://a.ffu.com
* About to connect() to a.ffu.com port 443 (#0)
*   Trying 10.89.9.129...
* Connected to a.ffu.com (10.89.9.129) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* NSS error -12286 (SSL_ERROR_NO_CYPHER_OVERLAP)
* Cannot communicate securely with peer: no common encryption algorithm(s).
* Closing connection 0
curl: (35) Cannot communicate securely with peer: no common encryption algorithm(s).

[root@localhost] ~$ curl -kI --tlsv1.0 https://b.ffu.com
HTTP/1.1 200 OK
Server: openresty
Date: Fri, 21 may 2024 09:52:55 GMT
Content-Type: text/html
Content-Length: 1097
Last-Modified: Fri, 06 Nov 2020 08:26:32 GMT
Connection: keep-alive
Vary: Accept-Encoding
ETag: "5fa508b8-449"
Accept-Ranges: bytes