NGINX 反向代理在后端服务器上因 TLSv1.3 失败

NGINX 反向代理在后端服务器上因 TLSv1.3 失败

我最近想将我所有的内部服务器从 TLSv1.2 切换到 TLSv1.3,因为它们都保持最新状态并且不需要支持旧设备。

我的设置是:

反向代理,地址为 192.168.20.2(Debian 11、NGINX v1.21.6)。这将终止公共有效的 Let 加密证书,并将继续使用 TLSv1.2 和 TLSv1.3 来支持各种客户端。请求通过另一个 TLS 会话通过 server_name 转发到正确的后端服务器 IP。

多个后端服务器,但为了简单起见,我们只讨论一个(所有配置都是相同的)。

后端服务器,地址为 192.168.30.2(Debian 11、NGINX v1.21.6)。这将终止另一个 TLS 会话(由反向代理启动,使用自签名内部证书),此时将提供 Web 服务器索引文件。

我的目标是在所有后端服务器上停用 TLSv1.2,因为 TLS 会话的客户端和服务器都由我控制,因此保持与新 TLS 版本的兼容性是可行的。

我进入了我在主站点配置中指出的 ssl-params.conf,并简单地TLSv1.2从该ssl_protocols部分中删除了它。重新启动 nginx 后(它确实重新启动得很好,没有错误),我尝试浏览该站点并获取502 Bad Gateway.

我认为问题可能出在删除 TLS1.2,但是在从反向代理本身运行curl 后,我能够正常获取 Web 服务器索引文件。因此,我认为问题出在反向代理 NGINX 服务器上。

我在这里可能缺少一些晦涩的 TLS NGINX 陷阱。
我在网上找不到任何东西,所以希望有人能指出我的问题?

如果您想知道为什么我对后端服务器使用 TLS,那是因为反向代理和后端服务器之间的连接跨越网络的不受信任部分,因此我进行加密。

以下是连接到特定后端站点的所有相关配置。

反向代理:

# configuration file /etc/nginx/nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}
http {
        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        server_tokens off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Rate Limiting
        ##

        limit_conn_zone $binary_remote_addr zone=limit_conn:1m;
        limit_conn limit_conn 100;
        limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;

        ##
        # Gzip Settings
        ##

        gzip on;

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        client_max_body_size 10000m;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/sites-enabled/*;

        ##
        # Hardening
        ##
 
        add_header Allow "GET, POST, HEAD" always;
}


# configuration file /etc/nginx/snippets/ssl-params.conf:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
resolver 192.168.20.1 valid=300s;
resolver_timeout 5s;

ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

# configuration file /etc/nginx/sites-enabled/wiki.domain.com:
server {
        listen 443 ssl http2;
        ssl_certificate /etc/letsencrypt/live/wiki.domain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/wiki.domain.com/privkey.pem;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_trusted_certificate /etc/letsencrypt/live/wiki.domain.com/chain.pem;
        include snippets/ssl-params.conf;
        server_name wiki.domain.com;
        location / {
                proxy_pass https://192.168.30.2;
                proxy_set_header X-Real-IP $remote_addr;
        }
}

后端服务器:

# configuration file /etc/nginx/nginx.conf:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # Logging Settings
        ##

        access_log off;
        error_log  off;

        ##
        # Gzip Settings
        ##

        gzip on;

        client_body_buffer_size 1K;
        client_header_buffer_size 1k;
        client_max_body_size 10k;
        large_client_header_buffers 2 1k;

        server_tokens off;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/sites-enabled/*;
}

# configuration file /etc/nginx/sites-enabled/dokuwiki.conf:
server {
    listen 443 ssl http2;
    include snippets/self-signed.conf;
    include snippets/ssl-params.conf;

    server_name _; 

    root         /var/www;
    index        index.html;
}

# configuration file /etc/nginx/snippets/self-signed.conf:
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;

# configuration file /etc/nginx/snippets/ssl-params.conf:
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 192.168.30.1 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'self';";
add_header X-XSS-Protection "1; mode=block";

ssl_dhparam /etc/ssl/certs/dhparam.pem;

我只是使用默认的index.html作为后端服务器进行测试。

当我尝试浏览时从客户端计算机到反向代理

user@clientmachine:~$ curl -vvvv https://wiki.domain.com
*   Trying PUBLICIP:443...
* Connected to wiki.domain.com (PUBLICIP) port 443 (#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 (OUT), TLS change cipher, Change cipher spec (1):
* 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 handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=wiki.domain.com
*  start date: May 17 09:56:32 2022 GMT
*  expire date: Aug 15 09:56:31 2022 GMT
*  subjectAltName: host "wiki.domain.com" matched cert's "wiki.domain.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  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 0x55619a9a25c0)
> GET / HTTP/2
> Host: wiki.domain.com
> user-agent: curl/7.74.0
> accept: */*
> 
* 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 502 
< server: nginx
< date: Mon, 13 Jun 2022 21:31:20 GMT
< content-type: text/html
< content-length: 150
< allow: GET, POST, HEAD
< 
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx</center>
</body>
</html>
* Connection #0 to host wiki.domain.com left intact

当我尝试浏览后端服务器时从反向代理到后端

user@revproxy:~$ curl -kvvvv https://192.168.30.2/
*   Trying 192.168.30.2:443...
* Connected to 192.168.30.2 (192.168.30.2) port 443 (#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 (OUT), TLS change cipher, Change cipher spec (1):
* 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 handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=US; ST=State; L=city; O=; CN=192.168.30.2
*  start date: Dec 10 16:29:30 2021 GMT
*  expire date: Feb 26 16:29:30 2031 GMT
*  issuer: C=US; ST=State; L=city; O=; CN=192.168.30.2
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* 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 0x555ab8d305c0)
> GET / HTTP/2
> Host: 192.168.30.2
> user-agent: curl/7.74.0
> accept: */*
> 
* 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
< date: Mon, 13 Jun 2022 21:33:38 GMT
< content-type: text/html
< content-length: 329
< last-modified: Mon, 13 Jun 2022 21:05:52 GMT
< etag: "62a7a6b0-149"
< strict-transport-security: max-age=63072000; includeSubdomains
< x-frame-options: DENY
< x-content-type-options: nosniff
< content-security-policy: default-src 'self';
< x-xss-protection: 1; mode=block
< accept-ranges: bytes
< 
<!DOCTYPE html>

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title>Spoon-Knife</title>
  <LINK href="styles.css" rel="stylesheet" type="text/css">
</head>

<body>

<!-- Feel free to change this text here -->
<p>
  Fork me? Fork you!
</p>
<p>
  I made a change
</p>

</body>
</html>
* Connection #0 to host 192.168.30.2 left intact

当然,如果我将其添加TLSv1.2到后端服务器上 ssl_protocols 部分的 ssl-params.conf 中,那么客户端请求会突然通过(客户端仍然使用 TLSv1.3 来初始连接到反向代理)

答案1

我在这里找到了解决方案: https://forum.nginx.org/read.php?11,294147

显然 NGINX 需要被告知使用什么协议来进行代理传递连接。

proxy_ssl_protocols TLSv1.3; 在反向代理服务器块中使用 解决了我的问题。

相关内容