必须配置双向认证并设SSLVerifyClient require、SSLCACertificateFile,再在<VirtualHost *:443>中写SSLOptions +StdEnvVars +ExportCertData,PHP才可通过$_SERVER['SSL_CLIENT_CERT']读取PEM证书。
要在 apache 虚拟主机中正确配置 ssloptions +exportcertdata,让 php、python 或其他后端能读取客户端证书内容(如 $_server['ssl_client_cert']),核心不是单独加这一行,而是必须构建完整的双向认证(mtls)上下文。否则该选项无效,环境变量不会生成。
必须启用强制客户端证书验证
Apache 不会在普通 HTTPS 连接中注入证书数据,+ExportCertData 只在客户端成功提交并被验证通过的证书场景下才生效。因此需明确要求验证:
- 在
<VirtualHost *:443>块内添加:SSLVerifyClient require(不推荐optional,易导致变量缺失) - 指定信任的 CA:用 SSLCACertificateFile 指向 PEM 格式的根证书文件,或 SSLCACertificatePath 指向含哈希符号链接的目录
- 确保客户端(浏览器/curl)实际携带了该 CA 签发的有效证书;否则握手失败或变量为空
在正确的虚拟主机作用域中设置 SSLOptions
SSLOptions 指令不支持嵌套继承,不能写在 <Directory> 或 <Location> 中——它只对当前 <VirtualHost> 生效:
- 放在
SSLEngine on后面、靠近开头的位置最稳妥 - 推荐组合写法:SSLOptions +StdEnvVars +ExportCertData(
+StdEnvVars提供基础 SSL 变量如协议、密钥交换方式,是常见依赖) - 避免使用
-ExportCertData或覆盖式写法,防止意外关闭
后端读取与调试要点
环境变量仅在 TLS 握手完成且证书校验成功后注入,PHP 中可直接访问:
-
$_SERVER['SSL_CLIENT_CERT'] 返回完整 PEM 字符串(含
-----BEGIN CERTIFICATE-----头尾) -
$_SERVER['SSL_CLIENT_VERIFY'] 应为
SUCCESS;若为NONE或空值,说明未触发验证或 CA 配置错误 - 临时加一段调试代码输出所有
SSL_*开头的$_SERVER键值,快速定位缺失环节
常见失效原因速查
如果配置后仍读不到证书,优先检查这几项:
- Apache 是否已加载
mod_ssl?运行apachectl -M | grep ssl确认 - 日志中是否有
Re-negotiation requested, but not allowed?如有,需禁用不安全重协商:SSLInsecureRenegotiation off - 是否用了反向代理(如 Nginx)?它默认不透传证书,需手动加
RequestHeader set X-Client-Cert "%{SSL_CLIENT_CERT}s" - phpenv 等轻量环境常缺 OpenSSL 完整支持,需确认其 Apache 编译时启用了
--with-ssl


















