SSLStrictSNIVHostCheck不校验证书域名匹配,仅控制SNI hostname路由:on时SNI不匹配即终止TLS握手,off时回退至首个HTTPS虚拟主机;它不影响浏览器后续的证书域名校验。
sslstrictsnivhostcheck 本身**不校验证书域名是否匹配**,它只检查客户端在 tls 握手时发送的 sni hostname 是否有对应配置的 virtualhost。证书本身的域名匹配(比如证书里有没有 www.example.com)由浏览器或客户端在收到证书后独立验证,apache 不干预这一步。
它真正控制的是“路由行为”
当多个 HTTPS 站点共用一个 IP 地址时,Apache 靠 SNI 字段决定把请求交给哪个 处理。SSLStrictSNIVHostCheck 就是管这个分发环节是否严格:
-
SSLStrictSNIVHostCheck on:如果客户端发了 SNI(比如
api.example.com),但 Apache 找不到 ServerName 或 ServerAlias 完全匹配的 VirtualHost,就直接终止 TLS 握手——用户看到的是连接失败、空白页或 ERR_SSL_PROTOCOL_ERROR,不是 HTTP 错误码。 - SSLStrictSNIVHostCheck off(默认):SNI 不匹配时,Apache 会退回到按配置文件顺序加载的第一个 HTTPS VirtualHost,用它的证书响应——哪怕证书里根本没有这个域名,也会发出,后续由浏览器报“证书域名不匹配”警告。
为什么不能靠它实现“强制证书域名匹配”
证书域名校验发生在 TLS 握手完成之后、HTTP 请求开始之前,属于客户端行为。Apache 的 mod_ssl 在握手阶段只做两件事:选对 VirtualHost、发对应证书。它不会读取证书内容去比对 SNI,也不拦截或重写证书内容。
换句话说:
– SNI 匹配失败 → SSLStrictSNIVHostCheck 决定是否拒连(TLS 层)
– SNI 匹配成功 → Apache 发出该 VirtualHost 的证书 → 浏览器自己检查证书里的 CN/SAN 是否含请求域名(应用层)
真正让证书域名匹配生效的关键配置
要确保用户访问 https://shop.example.com 时,收到的证书确实支持 shop.example.com,你需要:
- 每个
块中,ServerName 和 ServerAlias 必须与预期 SNI 值完全一致(区分大小写,不含端口或协议),例如:ServerName shop.example.comServerAlias api.example.com - SSLCertificateFile 指向的证书必须包含所有 ServerName/ServerAlias 域名,推荐使用 SAN(Subject Alternative Name)证书,而不是单域名证书。
- 避免通配符滥用:
*.example.com不覆盖example.com或admin.b.example.com,需显式列出或另配证书。
典型配置示例
以下是一个启用严格 SNI 路由 + 正确证书绑定的最小可用片段:
<virtualhost>
ServerName shop.example.com
ServerAlias admin.example.com
DocumentRoot /var/www/shop
SSLEngine on
SSLCertificateFile /etc/ssl/certs/shop.crt
SSLCertificateKeyFile /etc/ssl/private/shop.key
SSLCertificateChainFile /etc/ssl/certs/chain.pem
SSLStrictSNIVHostCheck on
</virtualhost>
注意:
– SSLStrictSNIVHostCheck on 必须写在 块内或 全局段中,不能放 .htaccess 或 httpd.conf 顶层;
– 若用户用旧设备(如 Android 4.0 以下)访问,它不发 SNI,此指令无效,请求仍会落到第一个 HTTPS VirtualHost —— 这是设计使然,不是 bug。











