当 Nginx 反向代理和上游服务器部署在不同位置的时候,如果 Nginx 和上游服务器通过 HTTP 通讯,就会存在中间人攻击的安全隐患。
比较安全的方式是反向代理服务器和上游服务器之间也通过 SSL 加密通讯来保证数据安全。
[客户端] <- SSL -> [Nginx 反向代理] <- SSL -> [上游服务器]
其中客户端和 Nginx 反向代理之间,使用的是正常的 SSL 证书。
Nginx 反向代理和上游服务器之间,可以使用同样的证书,也可以使用自签名证书。
上游服务器证书配置
没啥特别的地方,按正常方式配置就行,例子里面使用的是 CloudFlare 生成的有效期 15 年的自签名证书,好处就是不需要经常更新证书。
http {
server {
listen 127.0.0.1:10443 ssl http2;
listen [::1]:10443 ssl http2;
ssl_certificate /opt/certs/lvv.me/cloudflare/fullchain.pem;
ssl_certificate_key /opt/certs/lvv.me/cloudflare/privkey.pem;
ssl_trusted_certificate /opt/certs/lvv.me/cloudflare/fullchain.pem;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ecdh_curve prime256v1:secp384r1;
ssl_conf_command Options PrioritizeChaCha;
ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
}
}
stream {
upstream backend {
server 127.0.0.1:10443;
}
server {
listen 443;
listen [::]:443;
proxy_pass backend;
}
}
以上配置用了 stream 进行转发,这个操作不是必须的,仅供参考。
Nginx 反向代理服务器配置
反向代理服务器需要配置两个证书:客户端连接用的证书和上游服务器的证书。
反向代理需要配置在 stream 模块里:
stream {
upstream backend {
hash $remote_addr consistent;
server 1.2.3.4:443;
server 2.3.4.5:443;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /usr/local/etc/letsencrypt/live/lvv.me/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/lvv.me/privkey.pem;
ssl_trusted_certificate /usr/local/etc/letsencrypt/live/lvv.me/fullchain.pem;
ssl_protocols TLSv1.3 TLSv1.2;
ssl_ecdh_curve prime256v1:secp384r1;
ssl_conf_command Options PrioritizeChaCha;
ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
proxy_ssl on;
proxy_ssl_certificate /opt/certs/lvv.me/cloudflare/fullchain.pem;
proxy_ssl_certificate_key /opt/certs/lvv.me/cloudflare/privkey.pem;
proxy_ssl_trusted_certificate /opt/certs/lvv.me/cloudflare/fullchain.pem;
proxy_ssl_protocols TLSv1.3 TLSv1.2;
proxy_ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
proxy_ssl_session_reuse on;
proxy_connect_timeout 15s;
proxy_timeout 30s;
proxy_pass backend;
}
}
其中的 proxy_ssl
需要和上游服务器使用一样的 SSL 证书,
当用户访问 Nginx 反向代理的时候,数据先在反向代理这解密,然后使用上游服务器的证书加密通讯,整个通讯的链路都是经过 SSL 加密的,保证了安全性。
添加的 ssl_trusted_certificate
可以避免把完整的证书链发给客户端。