(
介绍
通常地,审查者可以选择封锁IP地址。当出现如此情况时,网站管理员可以选择更换服务器。不过,当此网站正在使用1个,正在被广泛使用的CDN提供商(例如Cloudflare),封锁此CDN的服务器将带来较大的附带损失;或是网站自身建立CDN,审查者并不知晓其所有服务器的IP地址。因此,若有必要,审查者将选择“DNS中毒攻击”与“SNI阻断”。
前者能够被轻易绕过(例如:“忽略伪造的数据包”“使用加密DNS”等);对于后者,可以选择使用TLS ECH。若不了解,这里将 简单地介绍它。若已了解其基本概念,可以选择跳转至“中间人攻击以‘强制域前置’”部分呀。
“加密客户端问候”
“加密客户端问候(Encrypted Client Hello, ECH)”为TLS协议(版本1.3)的1个扩展,它将TLS协议中,握手阶段的“Client Hello”数据包完全加密,同时 向外部暴露1个虚假的域名。通常地,客户端首先查询目标域名,其DNS记录中的HTTPS(类型65)记录或SVCB(类型64)记录,以得到“ECH配置”(可将其理解为“用于加密的公钥”),服务器则持有私钥。因此,客户端便可使用ECH开启握手,而避免第三方观察“Client Hello”数据包中的明文内容(最值得关注的,便是其中的SNI,通常为目标站点的域名)。
若防火墙没有封锁目标IP地址,由于ECH向外部暴露的SNI 并非目标域名,因此无法对其进行封锁。不过,由于ECH的外部SNI通常是固定的(例如,Cloudflare CDN使用cloudflare-ech.com作为其外部SNI),若防火墙封锁此SNI所指向的域名,将无法继续使用此ECH配置绕过封锁。
另外,为阅读之后的内容,应当略微了解“域前置”相关概念呀。
“域前置”
如上所述,TLS握手起始的“Client Hello”数据包中,存在“服务器名称指示(Server Name Indication,SNI)”,其指示客户端所访问的目标域名。它是明文内容,因此,审查者可以根据其中的内容,选择性地对客户端与服务器的连接进行干扰,即通常所述的“SNI阻断”。“域前置(Domain Fronting)”提供1种简单的思路:访问网站时,将SNI指定为 任意1个“未遭受SNI阻断的域名”,而实际访问的域名位于HTTP请求头Host中,部分网站仍能够进行正常的流量路由。由于HTTP协议内容被TLS协议包裹,第三方无法观察其中内容,以达到“未使用代理服务器时绕过审查”的目的。不过,它并不能使 被封锁的IP地址重回可用状态。
中间人攻击以“强制域前置”
2025年2月23日,Xray-core开发者于此评论中提及“使用Xray-core进行中间人攻击,以进行域前置”,以下流程 为它表示的基本思路呀:
- 程序信任Xray-core自签发的CA根证书。
- 程序与Xray-core建立TLS隧道,并向Xray-core发送TLS数据。
- Xray-core与目标网站建立TLS隧道。
- “Client Hello”中的SNI指向任意 未被封锁的网站。
事实上,其它用于中间人攻击的应用 亦可进行“强制域前置”。
提示:
不必仅为浏览器的请求域前置,而使用Xray-core。事实上,许多浏览器本身便支持“域前置”,对于具体设置,请参考此项目或以下视频:
https://www.youtube.com/watch?v=kbpxGOKVBSA
诚然,许多CDN提供商不允许用户使用域前置(例如,CloudFront不允许“Client Hello”中的SNI,与HTTP请求头的Host字段不相同) 仅有部分CDN(例如Cloudflare,Akamai等)允许它。
“Serverless For Iran”提供了实现以上思路的配置文件,同时包含“TCP分片”与“UDP噪音”。
对Cloudflare站点的“强制ECH”
根据Cloudflare的文档,Cloudflare的ECH功能为 处于“Free”计划的域名强制启用,仅非“Free”计划的域名可关闭。然而,即便网站管理员关闭Cloudflare的ECH选项,其仅从域名的HTTPS记录中 去除ech字段,但是,当客户端 向任意Cloudflare CDN服务器发送ECH时,若加密它所使用的“ECH配置”正确,仍能够正常进行TLS握手——Cloudflare仅处理ECH相关的DNS记录,ECH并没有被本质上影响——任何使用Cloudflare CDN的站点,均可使用ECH,以绕过防火墙的SNI阻断(例如*.workers.dev)。
Cloudflare对其所有域名,均使用相同的“ECH配置”。因此,只需寻找1个“未被SNI阻断,且使用Cloudflare CDN的网站(例如gitlab.io)”,从其DNS记录中 取得“ECH配置”,便可进行“强制ECH”呀。
RememberOurPromise:
似乎HTTPS记录中没有ECH Config值的Cloudflare网站都支持ECH,这下全部解锁直连了。
正好搭配CF workers vless,workers不能连的CF IP,可以直连。
使用方式
创建自签名CA证书
为了进行中间人攻击,需求1个自签名的CA证书。通过以下命令 便可创建它:
xray tls cert -ca -file="=CA证书文件名称="
证书文件=CA证书文件名称=.crt与私钥文件=CA证书文件名称=.key于当前目录被创建,将证书文件 添加至操作系统或程序的“受信任的证书颁发机构”列表,以便Xray-core实施中间人攻击。
配置
可以开始编写配置文件啦。从仅有1个“Socks”入站的配置文件开始:
{
"log": {
"loglevel": "info"
},
"dns": {},
"routing": {
"rules": [
{
"ip": [
"geoip:private"
],
"outboundTag": "freedom"
}
]
},
"inbounds": [
{
"tag": "socks",
"listen": "127.0.0.1",
"port": =“Socks”端口=,
"protocol": "socks"
}
],
"outbounds": [
{
"tag": "freedom",
"protocol": "freedom",
"settings": {
"domainStrategy": "ForceIP"
}
},
{
"tag": "blackhole",
"protocol": "blackhole"
}
]
}
添加1个“Tunnel”入站,它用于解密TLS流量,以进行“强制ECH”:
{
"inbounds": [
{
"tag": "tls_unpacker",
"listen": "127.0.0.1",
"port": =“Tunnel”端口=,
"protocol": "tunnel",
"settings": {
"port": 443,
"network": "tcp",
"followRedirect": true
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"alpn": [
"http/1.1",
"h2"
],
"certificates": [
{
"usage": "issue",
"certificateFile": "=CA证书目录==CA证书文件名称=.crt",
"keyFile": "=CA证书目录==CA证书文件名称=.key"
}
]
}
}
}
]
}
创建1个“Freedom”出站,以对“托管于Cloudflare的网站” 强制使用ECH:
{
"outbounds": [
{
"tag": "tls_repacker",
"protocol": "freedom",
"settings": {
"redirect": "=优选IP或优选域名=:443",
"domainStrategy": "ForceIP"
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"serverName": "FromMitm",
"verifyPeerCertInNames": [
"FromMitm"
],
"alpn": [
"FromMitm"
],
"fingerprint": "chrome",
"echConfigList": "=ECH配置=",
"echForceQuery": "full"
}
}
}
]
}
添加1个路由规则,将tls_unpacker所解密的内容,使用tls_repacker发出:
{
"routing": {
"rules": [
{
"inboundTag": [
"tls_unpacker"
],
"outboundTag": "tls_repacker"
}
]
}
}
由于此处的“强制ECH” 仅适用于“托管于Cloudflare的网站”,请自行添加1个出站,用于连接其它站点。此处选择使用“部署于Cloudflare Workers的EdgeTunnel(例如cmliu/edgetunnel)”服务呀:
{
"outbounds": [
{
"tag": "edgetunnel",
"protocol": "vless",
"settings": {
"address": "=用于EdgeTunnel的优选IP或优选域名=",
"port": 443,
"id": "=UUID=",
"encryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"host": "=EdgeTunnel的域名=",
"path": "/?ed=2560"
},
"tlsSettings": {
"serverName": "=EdgeTunnel的域名=",
"fingerprint": "chrome",
"echConfigList": "=ECH配置=",
"echForceQuery": "full"
}
}
}
]
}
通过ECH,可以绕过防火墙对*.workers.dev的SNI阻断,不必使用“自定义域”啦。
然后,只需配置路由规则:
- 将“目标IP地址属于Cloudflare CDN”的流量,通过
tls_unpacker入站,转到tls_repacker出站,以使用“强制ECH”直接连接它。 - 将“目标IP地址不属于Cloudflare CDN”的流量,通过
edgetunnel(或其它代理服务器)出站。
{
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"inboundTag": [
"socks"
],
"network": "tcp",
"port": 443,
"protocol": [
"tls"
],
"ip": [
"geoip:cloudflare"
],
"outboundTag": "redirector"
},
{
"inboundTag": [
"socks"
],
"ip": [
"geoip:!cloudflare"
],
"outboundTag": "edgetunnel"
}
]
},
"outbounds": [
{
"tag": "redirector",
"protocol": "freedom",
"settings": {
"redirect": "127.0.0.1:=“Tunnel”端口="
}
}
]
}
对于第1种情况,由于需要解密TLS数据,并再次进行路由,便通过redirector,将流量重定向至tls_unpacker所监听的端口。
随后,编写DNS相关配置,便大致完成呀:
{
"dns": {
"tag": "dns",
"hosts": {
"doh.pub": [
"1.12.12.12",
"120.53.53.53"
],
"alidns.com": [
"223.5.5.5",
"223.6.6.6"
]
},
"servers": [
"https://doh.pub/dns-query",
"https://alidns.com/dns-query"
]
}
}
由于防火墙通常封锁 向海外的DoH流量。若使用Cloudflare DoH,可将流量路由至redirector,以使用ECH;若使用其它 位于海外的DoH服务,通常需要使用其它代理服务器(例如上述的edgetunnel)呀:
{
"routing": {
"rules": [
{
"inboundTag": [
"dns"
],
"ip": [
"geoip:cn"
],
"outboundTag": "freedom"
},
{
"inboundTag": [
"dns"
],
"ip": [
"geoip:cloudflare"
],
"outboundTag": "redirector"
},
{
"inboundTag": [
"dns"
],
"outboundTag": "edgetunnel"
}
]
}
}
以下文本,应该能够表示流量的大致过程呀:
socks得到代理请求。- 若是TLS流量,且目标IP地址属于Cloudflare CDN:
tls_unpacker解密TLS数据。tls_repacker重新发出解密的数据,并使用ECH。
- 否则:
- 通过
edgetunnel发出数据。
- 通过
- 若是TLS流量,且目标IP地址属于Cloudflare CDN:
完整配置文件
{
"log": {
"loglevel": "info"
},
"dns": {
"tag": "dns",
"hosts": {
"doh.pub": [
"1.12.12.12",
"120.53.53.53"
],
"alidns.com": [
"223.5.5.5",
"223.6.6.6"
]
},
"servers": [
"https://doh.pub/dns-query",
"https://alidns.com/dns-query"
]
},
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"ip": [
"geoip:private"
],
"outboundTag": "freedom"
},
{
"inboundTag": [
"tls_unpacker"
],
"outboundTag": "tls_repacker"
},
{
"inboundTag": [
"socks"
],
"network": "tcp",
"port": 443,
"protocol": [
"tls"
],
"ip": [
"geoip:cloudflare"
],
"outboundTag": "redirector"
},
{
"inboundTag": [
"socks"
],
"ip": [
"geoip:!cloudflare"
],
"outboundTag": "edgetunnel"
},
{
"inboundTag": [
"dns"
],
"ip": [
"geoip:cn"
],
"outboundTag": "freedom"
},
{
"inboundTag": [
"dns"
],
"ip": [
"geoip:cloudflare"
],
"outboundTag": "redirector"
},
{
"inboundTag": [
"dns"
],
"outboundTag": "edgetunnel"
}
]
},
"inbounds": [
{
"tag": "socks",
"listen": "127.0.0.1",
"port": =“Socks”端口=,
"protocol": "socks",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
}
},
{
"tag": "tls_unpacker",
"listen": "127.0.0.1",
"port": =“Tunnel”端口=,
"protocol": "tunnel",
"settings": {
"port": 443,
"network": "tcp",
"followRedirect": true
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"alpn": [
"http/1.1",
"h2"
],
"certificates": [
{
"usage": "issue",
"certificateFile": "=CA证书目录==CA证书文件名称=.crt",
"keyFile": "=CA证书目录==CA证书文件名称=.key"
}
]
}
}
}
],
"outbounds": [
{
"tag": "edgetunnel",
"protocol": "vless",
"settings": {
"address": "=用于EdgeTunnel的优选IP或优选域名=",
"port": 443,
"id": "=UUID=",
"encryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "tls",
"wsSettings": {
"host": "=EdgeTunnel的域名=",
"path": "/?ed=2560"
},
"tlsSettings": {
"serverName": "=EdgeTunnel的域名=",
"fingerprint": "chrome",
"echConfigList": "=ECH配置=",
"echForceQuery": "full"
}
}
},
{
"tag": "tls_repacker",
"protocol": "freedom",
"settings": {
"redirect": "=优选IP或优选域名=:443",
"domainStrategy": "ForceIP"
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"serverName": "FromMitm",
"verifyPeerCertInNames": [
"FromMitm"
],
"alpn": [
"FromMitm"
],
"fingerprint": "chrome",
"echConfigList": "=ECH配置=",
"echForceQuery": "full"
}
}
},
{
"tag": "redirector",
"protocol": "freedom",
"settings": {
"redirect": "127.0.0.1:=“Tunnel”端口="
}
},
{
"tag": "freedom",
"protocol": "freedom",
"settings": {
"domainStrategy": "ForceIP"
}
},
{
"tag": "blackhole",
"protocol": "blackhole"
}
]
}
)