这篇文章将不会大量涉及 Reality 协议的原理,而是用尽可能简短的篇幅解释所谓“流量偷跑”背后的原因以及如何避免这类问题。
SNI 字段
HTTPS 的核心是 SSL/TLS 加密。在浏览器和服务器之间建立加密通道之前,必须先完成 TLS 握手。握手的一个关键步骤是:服务器必须向浏览器出示自己的 SSL/TLS 证书,以证明自己是被访问的目标网站,并且链接是可信的。
想象这样一个场景:一台具有 IPv4 地址的服务器之上托管着三个 HTTPS 网站,当有客浏览器发起请求时,服务器应该出示谁的证书?
现在问题来了:
浏览器通过IP地址,成功连接到了一台托管了
A.com、B.com和C.com三个网站的服务器。服务器收到了连接请求,但在加密开始之前,它并不知道到底是访问A、B、还是C。
那么,服务器应该出示哪个网站的证书?是A的,B的,还是C的?如果出示错了,浏览器就会报出严重安全警告,同时连接也会失败。
SNI(Server Name Indication,服务器名称指示)的诞生就是为了解决这个问题,它的工作流程如下:
在正式加密之前,浏览器会先明文发送一个 ClientHello 消息,其中包含了SNI字段,明确告诉服务器:“当前要访问的是
A.com这个网站”。服务器看到SNI后恍然大悟,从持有的众多证书中,准确地找出
A.com的证书,出示给浏览器。浏览器验证证书无误后,双方开始协商加密密钥,建立安全的加密通道。
所以,SNI字段存在的意义就在于:
在加密通信建立之前,预先以明文告诉服务器客户端想要访问的是哪个域名,以便服务器能提供正确的SSL/TLS证书,从而让单个IP地址能够服务于多个不同的HTTPS网站。
“回落”(Fallback)
GFW 的探测手段除了被动分析流量特征/深度包探测外,还会主动地向境外的可疑服务器发送探测数据包,模仿特定协议的握手过程。如果服务器的响应符合某个协议的特征,GFW就会确认这是一个代理服务器,并立即封锁IP地址。
如果有第三方尝试直接连接代理服务器IP,同时数据包未携带客户端密钥,则该数据包被判定为探测流量,此时会触发回落机制(Fallback)。Reality 服务器并不会暴露自己,而是会将这个连接请求直接转发到真实的目标网站。服务器在探测者面前就表现得像一个普通的反向代理服务器(即表现为对外转发),进一步增强了隐蔽性。
为了伪装的效果考虑,Xray对于鉴权失败(非合法reality请求)的流量,会直接转发至 target. 如果 target 网站的 IP 地址特殊(如使用了 CloudFlare CDN 的网站) 则相当于你的服务器充当了 CloudFlare 的端口转发,可能造成被扫描后偷跑流量的情况。 为了杜绝这种情况,可以考虑前置 Nginx 等方法过滤掉不符合要求的SNI。
–来自官方文档
由于回落机制的存在,任何来自非客户端的流量都将被导向 targetIP(协议配置中的 SNI 字段)。而所有来自非客户端的流量必定触发回落机制而被转发,一旦 targetIP 所对应的服务器受到反向代理保护,此时数据包不会直接被 targetIP 对应的服务器顺利接收,而是进入 CDN 网络等待进一步路由。
由数量众多的边缘节点构成的 CDN 网络类似于一台根据 SNI 字段做转发的代理服务器。整个过程中,不知名客户端通过 Reality 服务器的回落机制进入 CDN 网络,再次由 CDN 识别其数据包中 SNI 字段,并最终转发至对应 targetIP 的真实服务器。
为避免服务器在不知情的情况下成为 CDN 网络的反代,配置 Reality 时尤其注意避开隶属于 CDN 网络反向代理保护的域名作为伪装(尤其是Cloudflare,Gcore等),这类域名通常是 CDN 网络的直接入口。