apache客户端证书路径级授权需满足三前提:验证前置(sslverifyclient require须在顶层)、授权细粒度(用require ssl-verify-client+require expr替代sslrequire)、环境变量可信(ssloptions +stdenvvars且ca链完整)。

Apache 用 mod_ssl 做基于客户端证书的路径级授权,关键不在“能不能”,而在于「验证必须前置、授权必须细粒度、环境变量必须可信」——跳过任一环,SSLRequire 或 Require ssl-verify-client 都会失效或被绕过。
SSLVerifyClient require 必须在虚拟主机顶层启用
很多人把 SSLVerifyClient 放在 <directory></directory> 或 <location></location> 块里,结果发现客户端没弹证书选择框,或者请求直接 403。这是因为 mod_ssl 的证书验证是 TLS 握手阶段的事,必须在 SSL 引擎启动后、HTTP 请求解析前完成。
-
SSLVerifyClient require只能放在<virtualhost></virtualhost>作用域内(或全局 SSL 配置),不能嵌套在路径容器里 - 若只想对某路径强制验证,仍需在此处设为
require,再用Require指令做二次过滤 - 设成
optional后再靠SSLRequire判断,实际无法阻止未提供证书的请求进入 —— 此时SSL_CLIENT_VERIFY为NONE,但请求已通过
用 SSLRequire 过滤特定 CN 或 OU 字段
验证通过后,客户端证书信息会以环境变量形式暴露,如 SSL_CLIENT_S_DN_CN、SSL_CLIENT_S_DN_OU。这些变量可被 SSLRequire 表达式直接引用,但注意语法限制和空值风险。
-
SSLRequire %{SSL_CLIENT_S_DN_CN} eq "admin@example.com"是合法写法;但不能写成==或in,只支持eq/ge/le等 C 风格比较符 - 若客户端未提供证书,
%{SSL_CLIENT_S_DN_CN}为空字符串,eq "xxx"直接为 false,配合SSLVerifyClient require就能自然拦截 - 多个条件用
&&连接:SSLRequire %{SSL_CLIENT_S_DN_OU} eq "ops" && %{SSL_CLIENT_S_DN_CN} =~ /^dev-.*/ -
SSLRequire只在<directory></directory>或<location></location>内生效,且要求SSLOptions +StdEnvVars已启用(否则变量不可见)
现代 Apache 推荐用 Require ssl-verify-client + Require expr 替代 SSLRequire
从 Apache 2.4.8 起,SSLRequire 被标记为 legacy,官方推荐用统一的 Require 机制,更易与其它认证模块(如 LDAP)组合,也支持更灵活的表达式。
- 先确保加载了
mod_authz_core和mod_ssl,然后在路径块中写: -
Require ssl-verify-client:等价于旧版SSLVerifyClient require的路径级效果 -
Require expr %{SSL_CLIENT_S_DN_CN} == 'admin@example.com':支持完整字符串比较和正则(=~) - 组合使用:
Require all denied+Require ssl-verify-client+Require expr ...,用Satisfy all控制逻辑关系 - 注意:
Require expr中的变量名大小写敏感,必须是%{SSL_CLIENT_S_DN_CN},不是%{ssl_client_s_dn_cn}
CA 证书路径和 SSLVerifyDepth 容易导致“证书已安装但不被信任”
即使客户端证书本身有效,Apache 仍可能报 SSL alert: handshake failure 或日志出现 unable to get local issuer certificate,问题往往出在 CA 链配置上。
-
SSLCAcertificateFile必须指向**根 CA 或中间 CA 的 PEM 合并文件**,不能只放根 CA —— 如果客户端证书由中间 CA 签发,而你只配了根 CA,OpenSSL 验证链会断 -
SSLVerifyDepth 2表示最多允许“客户端证书 → 中间 CA → 根 CA”三级,若实际链更深(比如根 → 一级中间 → 二级中间 → 客户端),就得调成3 - 测试命令:
openssl verify -CAfile ca-bundle.pem client.crt,输出OK才说明链完整;否则要补全中间证书到 bundle 文件中 - 路径权限必须严格:Apache worker 进程用户(如
www-data)需有读取SSLCAcertificateFile的权限,否则静默失败
最常被忽略的是:客户端证书的 Basic Constraints 扩展必须允许其作为终端实体(CA:FALSE),且不能含 pathlen:0 等限制;否则即使所有配置都对,OpenSSL 在验证时也会拒绝该证书。这类问题只能靠 openssl x509 -text -in client.crt 查看扩展字段确认。











