问题描述
配置情况:
1.其他域名(b.example.com):未开启mTLS,使用通配符证书(*.example.com)
2.mTLS域名(a.example.com):开启mTLS,使用通配符证书(*.example.com)
问题情况:
在未验证(没有客户端证书)的情况下访问mTLS域名时:
开启HTPP2:
1.直接访问mTLS域名:
未验证无法访问(ERR_CONNECTION_CLOSED),符合预期
2.先访问其他域名,再访问mTLS域名,或通过js从其他域名跳转到mTLS域名:
意外的情况出现了,未验证有时候无法访问,有时候却可以访问成功,显示的内容是mTLS域名的,但证书是其他域名的证书
不开启HTTP2(HTTP1.1):
两种访问方式的结果均符合预期,未验证无法访问(ERR_EMPTY_RESPONSE)
问题原因
这是一个比较隐蔽的HTTP2连接复用导致的问题。我在配置mTLS时,对于服务端SSL证书,没有给mTLS域名使用单独的证书,而是用了可用于其他域名的证书
由于HTTP2激进的连接复用机制,如果先访问了其他域名,目标IP相同、证书可以通用,之前其他域名的连接可以复用(Keep-Alive),再访问mTLS域名时,浏览器会复用之前为其他域名建立的连接来请求mTLS域名,不会在网关L4层(传输层)触发新的握手,L7层(应用层)直接收到了访问请求。此时如果L7层没有进行额外校检,将可以请求到mTLS域名的内容,导致mTLS失效
解决方案
1.对于HTTP2,在配置SSL双向验证(mTLS)时,配置mTLS的域名不要和其他域名使用相同的/可通用的服务端SSL证书(证书隔离)
请为mTLS域名配置单独的证书,并确保其他域名的证书不可用于mTLS域名(尤其是在使用通配符、多域名证书时),这样先访问其他域名再访问mTLS域名时,连接不能被复用,只能发起新的TCP/TLS握手,防止mTLS被绕过
例如以下几种方案:
①其他未启用mTLS的域名使用通配符证书(三级域名):*.example.com,启用mTLS的域名使用单域名证书(四级域名):c.a.example.com,确保不在通配符覆盖范围内
②其他未启用mTLS的域名使用多域名证书:a.example.com、b.example.com,启用mTLS的域名使用单域名证书c.example.com,确保多域名证书里没有包含mTLS域名
③所有域名均使用单域名证书
2.对于HTTP2,如果可以修改网关配置,可以在网关L7层进行强制校验,如果HTTP2 Stream的:authority字段与当前连接TLS握手时的SNI不匹配,则拒绝请求,以nginx为例:
#核心代码
if ($host != $ssl_server_name) {
return 421;
}3.不开启HTTP2(不建议)
评论区