nginx代理java应用透传客户端真实证书需启用mtls并严格校验:开启ssl_verify_client on、配置ca证书与深度,用$ssl_client_escaped_cert等安全变量透传,java后端须主动解析x-client-*头并校验证书。

要在 Nginx 代理 Java 应用时透传客户端真实证书,核心是启用双向 TLS(mTLS),让 Nginx 先验证客户端证书,再安全地把关键身份信息转发给后端 Java 服务——不是直接转发原始 PEM 证书,而是用预处理后的字段,避免头字段非法或被截断。
必须开启并确认客户端证书验证
Java 后端能否信任证书信息,完全取决于 Nginx 是否真正完成了校验。以下配置缺一不可:
-
ssl_verify_client on; —— 强制要求客户端提供证书,不能用
optional - ssl_client_certificate /path/to/ca-bundle.crt; —— 指向可信 CA 的公钥文件(权限应为 644,不能含私钥)
- ssl_verify_depth 2; —— 覆盖常见证书链长度(根 CA + 中间 CA)
- 确保 Nginx 自身的
ssl_certificate和ssl_certificate_key已正确配置(服务端证书)
用安全变量透传证书内容
$ssl_client_cert 含换行符和空格,直接放进 HTTP Header 会破坏协议。推荐使用 Nginx ≥ 1.19.7 提供的转义变量:
-
proxy_set_header X-Client-Cert-Escaped $ssl_client_escaped_cert; —— URL 编码格式,后端可用
URLDecoder.decode()(Java)或java.net.URLDecoder.decode(..., "UTF-8")解码 - proxy_set_header X-Client-DN $ssl_client_s_dn; —— 主题名,已自动转义,可直接解析 CN/O/OU 等字段
- proxy_set_header X-Client-CN $ssl_client_s_dn_cn; —— 仅提取 Common Name,轻量且无格式风险
-
proxy_set_header X-Client-Verify $ssl_client_verify; —— 值为
SUCCESS/FAILED/NONE,后端据此快速拒绝未通过校验的请求
Java 后端需主动解析并校验
Nginx 只负责“发”,Java 应用必须显式读取这些 header,不能依赖 request.getRemoteAddr() 或默认证书机制:
- Spring Boot 中,禁用内建 SSL(不配
server.ssl.*),专注处理转发头 - 在 Controller 或 Filter 中读取:
String certEscaped = request.getHeader("X-Client-Cert-Escaped");String dn = request.getHeader("X-Client-DN");String verify = request.getHeader("X-Client-Verify"); - 若需验签或查白名单,解码后用
CertificateFactory加载 X.509 证书,再比对指纹($ssl_client_fingerprint,需 Nginx ≥ 1.19.0)或 DN 字段 - 建议结合 Spring Security 的
PreAuthenticatedAuthenticationProvider实现基于证书 DN 的免密登录
配套基础透传不能少
证书身份需与请求上下文匹配,否则无法关联操作行为:
-
proxy_set_header X-Real-IP $remote_addr; —— 配合
set_real_ip_from和real_ip_header使用,确保 IP 不被伪造 - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; —— 多层代理时保留链路
- proxy_set_header X-Forwarded-Proto $scheme; —— 让 Java 知道原始是 HTTPS,避免重定向循环
- proxy_set_header Host $host; —— 保持原始 Host,保障 Cookie 和跳转逻辑正确
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











