Apache中实现内部系统双向认证必须闭环配置CA证书、SSLVerifyClient require指令及Location路径控制,缺一不可;全局启用会导致静态资源403,需在/api或/admin等业务路径下精准启用,并透传SSL_CLIENT_S_DN等变量供后端校验。

在 Apache 中用 mod_ssl 配置 SSLVerifyClient 实现内部系统双向认证,关键不是“开了 verify 就能用”,而是整套信任链、指令协同和路径控制必须闭环。内部系统场景下,客户端固定、证书可统一签发、不面向公网用户,这反而让双向认证更可控、更安全。
必须配齐的三要素:CA 证书 + require 指令 + 正确作用域
只设 SSLVerifyClient require 会直接返回 500 错误,日志里出现 peer did not return a certificate —— 这不是客户端没发,是服务端根本没准备好验证它。
-
SSLCACertificateFile 必须指定,指向你自建根 CA 的 PEM 文件(如
/etc/apache2/ssl/ca.crt),不能是私钥,也不能混入注释或多余空行 -
SSLVerifyClient require 是唯一生产可用选项;
optional形同未启用,optional_no_ca不验签名,仅调试用 - 不要在全局
里直接写require,否则所有静态资源(CSS/JS/图片)都强制要证书,浏览器通常不会自动发送,导致大量 403
精准控制在哪条路径启用双向认证
内部系统往往只有 API 接口或管理后台需要强身份核验,前端页面、公共资源仍走单向 HTTPS 即可。用 做最小粒度控制:
- 在
/api/或/admin/下启用:<location><br> SSLVerifyClient require<br> SSLRequireSSL<br></location>
- 若需按组织单位(OU)或通用名(CN)做权限初筛,可用:
Require expr %{SSL_CLIENT_S_DN_OU} == 'Finance' && %{SSL_CLIENT_VERIFY} == 'SUCCESS'
(Apache 2.4.8+ 推荐,替代已废弃的SSLRequire) - 确保该 Location 内不包含
AllowOverride All等可能覆盖 SSL 指令的配置
让后端应用真正用上客户端身份
Apache 验证通过后,证书信息默认不透传。你需要显式注入 HTTP 头或环境变量供后端识别:
- 透传完整主题名:
RequestHeader set X-Client-DN "%{SSL_CLIENT_S_DN}s" - 透传验证状态(用于快速拦截异常):
RequestHeader set X-SSL-Verify "%{SSL_CLIENT_VERIFY}s" - 若后端是 Java 应用,也可用
SetEnvIf注入 CGI 变量:SetEnvIf SSL_CLIENT_VERIFY "SUCCESS" SSL_CLIENT_VALID=1 - 注意:这些头字段需在后端明确读取并校验,不能只依赖 Apache 的验证结果
验证与排障要点
配置完别急着 reload,先过这几关:
- 执行
apachectl configtest,确认语法无误;文件权限设为600,属主为运行 Apache 的用户(如www-data) - 用 curl 测试是否真触发双向握手:
curl -k --cert client.pem --key client.key https://your.internal/api/v3/status - 查看 Apache error log,重点搜
SSL Library Error和SSL handshake failed;成功时应有Verified client certificate类日志 - 浏览器访问时,若弹出证书选择框但选后仍 403,大概率是客户端证书未被 CA 文件信任,或证书已过期/吊销











