RewriteCond 无法可靠判断客户端支持的 TLS 版本,因其仅能访问协商后的 SSL_PROTOCOL 变量,而非 ClientHello 中声明的支持版本;TLS 握手早于重写规则执行,且虚拟主机通常禁用相关环境变量。
虚拟主机通常不支持直接配置 mod_rewrite 的 rewritecond 来判断客户端 tls 版本,因为 apache 无法在 rewrite 规则中直接获取 tls 协议版本信息。tls 握手发生在 http 请求之前,而 rewritecond 只能访问 http 请求头、环境变量或服务器变量(如 https、http_host),但 ssl_protocol 这类变量仅在启用 mod_ssl 且使用 ssl/tls 连接时可用,且它反映的是当前连接的协议(如 tlsv1.2),**不是客户端“声明支持”的 tls 版本,而是实际协商成功的版本**。
为什么 RewriteCond 不能可靠判断客户端支持的 TLS 版本
客户端支持的 TLS 版本(如 TLS 1.0/1.1/1.2/1.3)是在 ClientHello 中发送的,Apache 不向 rewrite 模块暴露该原始握手数据。即使使用 %{SSL_PROTOCOL},它只表示本次连接最终协商采用的协议,无法区分是客户端降级导致还是服务端限制所致。
-
虚拟主机权限受限:共享虚拟主机通常禁用
SSLOptions +StdEnvVars或不允许设置RewriteCond %{SSL_PROTOCOL} ^TLSv1\.0$等条件;即使允许,也仅反映已建立连接的协议,不是“探测客户端能力”。 -
无标准环境变量对应 ClientHello 内容:Apache 不提供类似
%{TLS_CLIENT_SUPPORTED_VERSIONS}的变量,这类信息需通过 OpenSSL API 在 SSL 模块层解析,rewrite 模块无权访问。 - 重写规则执行时机晚于 TLS 协商:当 rewrite 引擎运行时,TLS 已完成握手,只能看到结果,无法干预或检测初始协商能力。
更可行的替代方案
若目标是拒绝低版本 TLS 客户端访问,应通过 Web 服务器 TLS 配置层实现,而非 rewrite:
-
在 Apache 主配置或 SSL 虚拟主机中设置
SSLProtocol:SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
这会强制 Apache 拒绝 TLS 1.0/1.1 握手,客户端根本无法建立连接,比 rewrite 更早、更安全。 -
检查是否启用
mod_ssl和正确 SSL 配置:确认虚拟主机支持自定义 SSL 配置(多数共享主机不开放此项;VPS 或独立服务器可操作)。 -
用应用层逻辑辅助识别(有限场景):例如 PHP 中读取
$_SERVER['SSL_PROTOCOL'](值如TLSv1.2),再做日志记录或跳转——但这仍是“已协商版本”,非探测用途。
如果必须在 .htaccess 中做简单区分(仅限已知环境)
某些托管环境(如 cPanel + Apache with mod_ssl enabled)可能导出 SSL_PROTOCOL 到 CGI 环境,可在 .htaccess 中尝试(但成功率低,且不推荐用于安全控制):
RewriteEngine On
# 仅当实际连接为 TLSv1.0 时重定向(不推荐用于安全拦截)
RewriteCond %{SSL_PROTOCOL} ^TLSv1\.0$
RewriteRule ^(.*)$ https://example.com/tls-unsupported/ [R=302,L]
⚠️ 注意:此规则仅对已成功建立 TLSv1.0 连接的请求生效,无法阻止 TLSv1.0 握手本身,存在安全窗口;且多数虚拟主机不支持该变量在 .htaccess 中生效。
总结建议
不要依赖 RewriteCond 判断客户端 TLS 支持能力。真正的 TLS 版本控制必须在 SSL/TLS 协议层完成:升级 OpenSSL、配置 SSLProtocol 和 SSLCipherSuite、禁用弱协议。rewrite 是 HTTP 层工具,不适合处理传输层安全策略。如虚拟主机不提供 SSL 配置权限,应联系服务商升级默认 TLS 设置,或迁移到支持自主 SSL 配置的托管环境。

















