我在装有 OpenSSL 1.1.1 的 Ubuntu 18.04.02 LTS 系统上运行 NGINX 1.14.0。到目前为止,我们仅使用 TLSv1.3 来支持浏览器,但现在有第三方想要进行 api 调用,而他们只有对 TLSv1.2 的库支持。因此,nginx 检查路径、auth 标头的存在,然后转发:
location ~ ^/api/v2/blah {
if ($http_authorization = '') {
return 403;
}
include uwsgi_params;
uwsgi_read_timeout 512;
uwsgi_send_timeout 512;
uwsgi_pass lis_django;
}
ssl_protocols TLSv1.2 TLSv1.3;
我以为这只是在服务器配置中指定的简单问题,但客户端报告了连接问题。
事实上,使用 curl 明确使用 tlsv1.2:
curl -v --tlsv1.2 --tls-max 1.2 --location \
--request GET https://example.com:53303/api/v2/blah' \
--header 'Authorization: Token 606986de557cd5ca037d0.....'
生成:
Note: Unnecessary use of -X or --request, GET is already inferred.
* Trying x.x.x.x:53303...
* TCP_NODELAY set
* Connected to example.com (x.x.x.x) port 53303 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS alert, protocol version (582):
* error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
* Closing connection 0
curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
我已经ssl_protocol: TLSv1.2;
在所有虚拟服务器上进行了设置,但问题仍然存在。nginx 在明确配置的情况下怎么会不支持 TLSv1.2?
更多细节
我使用的是打包的 deb,但是 nginx 是使用以下内容构建的:
nginx version: nginx/1.14.0 (Ubuntu)
built with OpenSSL 1.1.1 11 Sep 2018
TLS SNI support enabled
configure arguments:
--with-cc-opt='-g -O2
-fdebug-prefix-map=/build/nginx-GkiujU/nginx-1.14.0=.
-fstack-protector-strong
-Wformat
-Werror=format-security
-fPIC
-Wdate-time
-D_FORTIFY_SOURCE=2'
--with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx
--conf-path=/etc/nginx/nginx.conf
--http-log-path=/var/log/nginx/access.log
--error-log-path=/var/log/nginx/error.log
--lock-path=/var/lock/nginx.lock
--pid-path=/run/nginx.pid
--modules-path=/usr/lib/nginx/modules
--http-client-body-temp-path=/var/lib/nginx/body
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi
--http-proxy-temp-path=/var/lib/nginx/proxy
--http-scgi-temp-path=/var/lib/nginx/scgi
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi
--with-debug
--with-pcre-jit
--with-http_ssl_module
--with-http_stub_status_module
--with-http_realip_module
--with-http_auth_request_module
--with-http_v2_module
--with-http_dav_module
--with-http_slice_module
--with-threads
--with-http_addition_module
--with-http_geoip_module=dynamic
--with-http_gunzip_module
--with-http_gzip_static_module
--with-http_image_filter_module=dynamic
--with-http_sub_module
--with-http_xslt_module=dynamic
--with-stream=dynamic
--with-stream_ssl_module
--with-mail=dynamic
--with-mail_ssl_module
我有基础nginx.conf
和 a site_nginx.conf
。/etc/nginx/sites-enabled
每个服务器配置都使用相同的 SSL 配置:
ssl_protocols TLSv1.3 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM,EDH+AESGCM,ECDHE-ECDSA-AES256-CCM8";
ssl_dhparam /etc/nginx/dhparam;
当我使用 curl 明确说明 TLSv1.3 时:
Note: Unnecessary use of -X or --request, GET is already inferred.
* Trying x.x.x.x:53303...
* TCP_NODELAY set
* Connected to staging.example.com (x.x.x.x) port 53303 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=staging.example.com
* start date: Jul 2 02:05:47 2020 GMT
* expire date: Sep 30 02:05:47 2020 GMT
* subjectAltName: host "staging.example.com" matched cert's "staging.example.com"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55f7b9791db0)
> GET /api/v2/blah/TQ000003 HTTP/2
> Host: staging.example.com:53303
> user-agent: curl/7.68.0
> accept: */*
> authorization: Token 606986de5...............
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< server: nginx/1.14.0 (Ubuntu)
< date: Sun, 19 Jul 2020 23:31:08 GMT
< content-type: application/json
< content-length: 327
< allow: GET, HEAD, OPTIONS
< x-frame-options: SAMEORIGIN
< vary: Cookie
<
* Connection #0 to host staging.example.com left intact
我还查看了 curl 中的 TLSv1.2 密码支持https://curl.haxx.se/docs/ssl-ciphers.html并将 ECDHE-ECDSA-AES256-CCM8 明确添加到 nginx.conf。然后尝试使用 --ciphers 参数:
curl -v --tlsv1.2 --tls-max 1.2 --ciphers ECDHE-ECDSA-AES256-CCM8 --location --request GET 'https://staging.example.com:53303/api/v2/blah/TQ000003' --header 'Authorization: Token 606986de5...........'
但结果类似:
Note: Unnecessary use of -X or --request, GET is already inferred.
* Trying x.x.x.x:53303...
* TCP_NODELAY set
* Connected to staging.example.com (x.x.x.x) port 53303 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ECDHE-ECDSA-AES256-CCM8
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS alert, protocol version (582):
* error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
* Closing connection 0
curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
使用 OpenSSL 客户端 openssl s_client 产生:
openssl s_client -tls1_2 --connect staging.example.com:53303
CONNECTED(00000003)
139791010735424:error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version:../ssl/record/rec_layer_s3.c:1543:SSL alert number 70
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 223 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1595275021
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no
---
答案1
TLS 1.3 具有它自己的密码列表这些是固定的,不需要指定,但 TLS 1.2 没有。您需要ssl_ciphers
在启用 TLS 1.2(或更低版本)时指定。
适用于所有现代 TLS 1.2 客户端的最低配置是:
ssl_protocols TLSv1.3 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM,EDH+AESGCM";
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl_dhparam /etc/nginx/dhparam.pem;
指定的密码列表仅适用于 TLS 1.2。TLS 1.3 则使用内部固定密码列表。
查看Mozilla SSL 配置生成器如果您需要启用额外的密码来兼容奇怪的客户端。