开启 ssl_prefer_server_ciphers on 是让 Nginx 在 TLS 握手时主导加密算法选择的关键,但必须配合精简强密码套件、限定 TLSv1.2+ 协议、指定安全 ECDH 曲线及分层验证,才能确保反代层端到端安全。

开启 ssl_prefer_server_ciphers on 是让 Nginx 反向代理层在 TLS 握手时掌握加密算法主导权的关键一步,但它本身不决定强弱——真正起作用的是你如何配置整套策略,并确保它在反代场景下不被上游或下游干扰。
必须放在 server 块中,且与 proxy_pass 共存无冲突
反代服务常有多个 server 块(如 HTTP 跳转、HTTPS 服务、API 子路径),ssl_prefer_server_ciphers 必须明确写在承载 HTTPS 的那个 server 块内,不能只靠 http 块全局设置。否则可能出现:主站生效,但 /api 或 /static 子路径因 location 继承问题降级。
- 避免在
location块里重复或覆盖该指令;它不支持 location 级别作用域 - 若使用了
proxy_ssl_*相关参数(如proxy_ssl_protocols),注意那是控制「Nginx 到后端」的连接,和本指令无关;本指令只影响「客户端到 Nginx」这一段 - 确认没有被 include 文件中的低优先级配置覆盖(例如某 conf 片段写了
ssl_prefer_server_ciphers off)
ssl_ciphers 必须精简、排序、剔除所有非 PFS 套件
反代层若仍保留 RSA 密钥交换类套件(如 AES128-SHA),即使排在最后,也可能被旧客户端或中间设备诱导协商成功——这不是理论风险,是真实发生过的降级案例。
- 推荐直接使用明确现代列表,例如:
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 - 禁用必须写全:
!RC4:!MD5:!SHA1:!DES:!3DES:!EXPORT:!aNULL:!eNULL:!PSK:!SRP:!CAMELLIA - 不要用
HIGH或!aNULL:!MD5这类模糊表达——它们无法排除 SHA1 签名或非前向保密套件
协议与密钥交换参数要同步收紧
反代层的安全边界由最弱一环决定。哪怕 cipher list 很强,若允许 TLSv1.1 握手,攻击者仍可触发降级;若 ECDH 曲线未指定,部分客户端可能 fallback 到 RSA 密钥交换。
- 强制协议版本:
ssl_protocols TLSv1.2 TLSv1.3;(TLSv1等价于 TLSv1.0,已淘汰) - 指定安全曲线:
ssl_ecdh_curve secp384r1:prime256v1;,兼顾性能与兼容性 - 启用会话复用:
ssl_session_cache shared:SSL:10m; ssl_session_timeout 4h;,减少重复握手带来的协商不确定性
验证必须分层进行,不能只看单点结果
反代环境存在多层协商可能(客户端→Nginx→后端),验证重点永远是「客户端到 Nginx」这一段是否受控。
- 用 OpenSSL 强制测试 TLSv1.2:
openssl s_client -connect yourdomain.com:443 -tls1_2 2>/dev/null | grep "Cipher is",输出应为你的ssl_ciphers列表最左侧那个套件 - 用 SSL Labs 扫描,重点关注 “Handshake Simulation” 中各浏览器实际协商结果,确认 iOS 13+、Chrome 90+、Firefox 85+ 等主流客户端都落在 GCM/ChaCha20 区间
- 检查 Nginx error log,确认无
no suitable signature algorithm或ssl handshake failed类报错——这说明某些客户端因严格策略被拒,需结合日志判断是否属预期行为


















