apache不直接支持基于客户端证书序列号黑名单拦截,但可通过mod_ssl环境变量ssl_client_m_serial配合mod_rewrite或require指令实现:启用sslverifyclient require和ssloptions +stdenvvars后,用rewritecond匹配序列号并返回403,或用require expr进行多条件比对。

Apache 本身不直接支持基于客户端证书序列号(Serial Number)做黑名单拦截,但可通过组合 mod_ssl 环境变量、mod_rewrite 或 mod_authz_core + 自定义逻辑实现。核心思路是:让 Apache 在 TLS 握手后获取客户端证书序列号,再在请求处理阶段比对预设黑名单,匹配即拒绝。
获取客户端证书序列号的关键配置
客户端证书序列号在握手验证成功后,会以环境变量形式暴露,但不是默认提供,需启用特定选项:
- 必须先启用双向认证:
SSLVerifyClient require - 启用标准 SSL 环境变量:
SSLOptions +StdEnvVars(放在<virtualhost></virtualhost>或<location></location>内) - 序列号由环境变量
SSL_CLIENT_M_SERIAL提供(十六进制大写、无分隔符,如1A2B3C4D5E6F7890);也可用SSL_CLIENT_S_DN解析完整 DN,但序列号更稳定、唯一性强
用 mod_rewrite 实现黑名单拦截(推荐,无需额外模块)
适用于简单黑名单(少量固定序列号),直接在虚拟主机或目录配置中添加:
RewriteEngine On
RewriteCond %{SSL:SSL_CLIENT_M_SERIAL} ^1A2B3C4D5E6F7890$ [OR]
RewriteCond %{SSL:SSL_CLIENT_M_SERIAL} ^FEDCBA9876543210$
RewriteRule ^ - [F]
-
%{SSL:SSL_CLIENT_M_SERIAL}是访问 SSL 环境变量的正确语法(%{SSL_CLIENT_M_SERIAL}在 Rewrite 中无效) -
[F]返回 403 Forbidden;也可用[R=403]或结合自定义错误页 - 多个序列号用
[OR]连接;末尾无[OR],避免误判
用 Require 指令配合外部脚本或映射表(适合动态/大量条目)
当黑名单条目较多或需定期更新时,可借助 Require expr 或外部授权机制:
- 使用表达式判断(Apache 2.4.13+):
Require expr %{SSL:SSL_CLIENT_M_SERIAL} != "1A2B3C4D5E6F7890" && %{SSL:SSL_CLIENT_M_SERIAL} != "FEDCBA9876543210" - 或通过
authnz_external模块调用 Shell/Python 脚本查黑名单文件,将序列号作为参数传入,返回 OK/FAIL - 注意:若用
Require ssl-verify-client,它只校验证书存在性,不参与序列号比对,需单独加逻辑
补充要点与常见问题
确保整个链路有效运行,还需注意:
- CA 证书必须可信且路径正确(
SSLCACertificateFile),否则客户端证书无法通过验证,SSL_CLIENT_M_SERIAL将为空 - 浏览器或 curl 必须实际携带证书;测试时可用:
curl --cert client.crt --key client.key https://host/sec - 日志中调试可用:
LogFormat "%h %l %{SSL:SSL_CLIENT_M_SERIAL}e %t \"%r\" %>s" sslserial配合CustomLog - 序列号为十六进制字符串,大小写敏感;建议统一转大写存储和比对











