sslusername仅支持绑定预定义变量如ssl_client_s_dn_uid,需配合sslverifyclient require、sslrequiressl及ssloptions +stdenvvars启用;证书必须含uid字段,且后端需正确解码url编码值。
要通过虚拟主机配置 sslusername 指令将证书中的 uid 字段导出至后端应用系统,关键不是“导出”动作本身,而是让 apache 正确提取并注入该字段为环境变量(如 ssl_client_s_dn_uid),再由后端(如 php、python wsgi、cgi 等)读取使用。整个过程依赖严格的前提条件和精确的配置顺序。
必须启用双向认证与环境变量透传
SSLUserName 不会自动生效,它只在客户端证书验证成功后才起作用:
-
强制客户端提供证书:在
<virtualhost></virtualhost>块中必须设置SSLVerifyClient require;仅设optional或不设,SSL_CLIENT_S_DN_*全为空 -
限定 HTTPS 访问:添加
SSLRequireSSL(或确保该站点仅监听 443 且无 HTTP 回退) -
透传变量给后端:Apache 2.4+ 需在对应
<directory></directory>或<location></location>中加入SSLOptions +StdEnvVars,否则 PHP 的$_SERVER或 CGI 环境里看不到SSL_CLIENT_S_DN_UID
确认证书实际包含 UID 字段
SSLUserName 只能绑定已解析出的字段,而 SSL_CLIENT_S_DN_UID 是否可用,取决于客户端证书是否在 Subject 中嵌入了 UID=xxx:
- 公网 CA(如 Let’s Encrypt、DigiCert)签发的证书通常不含
UID,该字段多见于企业私有 CA 或 LDAP 集成场景 - 可用命令快速验证:
openssl x509 -in client.crt -text -noout | grep -i "uid" - 若输出为空,说明证书没带 UID,
SSL_CLIENT_S_DN_UID恒为空字符串,后续绑定无效
在 VirtualHost 中正确配置 SSLUserName
语法极简,但容错率低,不能拼接、不能正则、不能空格处理:
- 直接写:
SSLUserName SSL_CLIENT_S_DN_UID(推荐,最稳妥) - 不要写:
SSLUserName "UID=${SSL_CLIENT_S_DN_UID}"(语法错误,mod_ssl 不支持变量插值) - 注意编码:UID 值若含空格或特殊字符,会被自动 URL 编码(如
user name→user+name),后端需调用urldecode()或等效函数解码后再使用
后端应用如何获取该值
配置生效后,该值作为 CGI 环境变量暴露,不同后端读取方式不同:
-
PHP:可通过
$_SERVER['SSL_CLIENT_S_DN_UID']获取(需开启SSLOptions +StdEnvVars) -
Python WSGI:在
environ字典中查找键SSL_CLIENT_S_DN_UID -
Node.js(HTTP 模块):需 Apache 用
mod_proxy转发时显式设置请求头,例如:RequestHeader set X-Client-UID "%{SSL_CLIENT_S_DN_UID}e",再由 Node.js 读X-Client-UID头











