TLS 握手中的 SNI
客户端在向服务器进行 TLS 握手时,会发送一个叫作 SNI(Server Name Indication)的信息。
为啥要这么做?因为一台服务器完全可能把好几张不同的 TLS 证书挂在同一个 IP 上。要是握手时不说清楚「我要找谁」,服务器就一脸懵:这么多证书,到底该拿哪张出来见客?
先捋一捋时间线
- DNS 查询:把域名翻译成 IP 地址。
- TCP 三次握手:敲开该 IP 的 443 端口大门。
- TLS 握手:协商加密参数、验证证书。SNI 就藏在这一步的 ClientHello 里,是整个流程里「自报家门」的关键时刻。
- HTTP 请求:终于可以通过加密通道安心传数据啦。
站在 ISP 的视角
先说 DNS 查询。它通常是明文的,ISP 一眼就能看穿。就算你用了加密 DNS,ISP 也能看到你在和某个 DNS 服务器聊天,只是不一定知道你具体问了啥。这类流量一般都会被放行。TCP 握手也一样,平平无奇,没什么特别之处,通常也是直接放行。
那么问题来了:如果 ISP 想拦截某些域名,或者只放行白名单里的域名,该从哪下手呢?
答案就是 TLS 握手的第一步,靠 SNI 判断你的目的地。客户端一发起 TLS 握手,在 ISP 眼里就等于大声宣布:「我要去访问某某网站啦!」放不放行,全看它自己的策略。
关于 ECH(Encrypted ClientHello),这里先按下不表。
想打断你的连接也不难,可以在中间动点手脚:给通信双方各发一个 TCP RST,或者干脆直接丢包,让你干等着。
SNI 欺骗:披一件马甲
再从网络代理的角度聊聊,SNI 欺骗为什么行得通。
关键在于你有一台中间商 VPS:流量先到 VPS,再由它转发到真正的目的地。所以在和 VPS 建立 TLS 连接时,你完全可以把 SNI 填成别的域名。明明连的是自己的 VPS,却在 SNI 里一本正经地说:「啊,我是 Google。」这样一来,ISP 看到的可能就是你正在老老实实访问 Google。
所以,观察 SNI 确实是一种行之有效的流量控制手段。总体来说,是的。
但是,SNI 并不是干这个的
我想强调一下,SNI 的设计初衷从来不是用来做流量识别和访问控制的,被拿来干这个活,局限性自然不少。
场景一:宁可错杀一千的防火墙
对于那些宁可错杀一千、不可放过一个的 ISP 或防火墙来说,如果你声称的 SNI 太出名了,比如 Microsoft、Google,它们很可能会多留个心眼,进一步检查目标 IP 是不是已知的数据中心或机房,再按自己的策略决定放不放行。
这时候,相对稳妥的做法是使用 VLESS/VMess + TLS,配上自己的域名和证书,老老实实做人。
场景二:只做简单域名管理的场景
另一类场景,只是用 SNI 做点简单的域名访问权限管理,比如飞机上、火车上的 Wi-Fi:部分域名免费访问,其余的要掏钱。
这种情况下,VLESS + Reality 配合修改 SNI,就有可能绕过这种基于 SNI 的简单访问控制。
以上,纯属技术角度的随想。