利用DoH+ECH+中继代理打造抗审查网络

本文章仅提供思路进行学习交流,具体代码因为合规问题暂不提供。

前提条件: 要访问的目标网站必须支持 ECH,并且其 CDN 的 IP 没有被全面封锁。

适用范围: 本文主要针对托管在 Cloudflare (CF) 上的网站,其他 CDN 原理类似。

核心架构: 自建智能 DoH + ECH 加密握手 + 选择性中继代理

知己知彼——防火墙是如何阻断连接的?

1. DNS 污染(最常见)

原理: 拦截 UDP 53 端口的明文 DNS 查询。

过程: 当你查询 x.com 时,防火墙识别到黑名单域名,不等上游真正返回结果,直接抢答一个虚假 IP。你连上假 IP,自然访问失败。

解决方案:使用 DoH (DNS over HTTPS)

2. IP 黑名单封禁

原理:防火墙维护着一张黑名单 IP 列表(可能是全端口封禁,也可能仅封 443 端口)。

过程:只要发现你的 TCP 数据包目标 IP 在名单内,直接丢弃或发送 RST 包重置,导致三次握手失败。

解决方案:使用 中继代理 改变目标 IP

3. SNI 检测

原理:在传统的 TLS 握手阶段(不带 ECH),ClientHello 报文中的 SNI(服务器名称指示)是明文的。

过程:防火墙抓到 TCP 443 流量,读取明文 SNI。如果命中黑名单,直接强行断开连接。

ECH 的作用:把真实 SNI 藏进加密内层 ClientHello,防火墙读取不到真实域名,无法用 SNI 规则阻断。 但注意:防火墙依然可以看到目标 IP。只要 IP 被封禁,ECH 也救不了。

解决方案:使用 ECH (Encrypted Client Hello)。把真实域名藏进加密内层,防火墙只能看到伪装的外层域名。(注意:如果CDN的公共域名也被阻断了,ECH 也救不了)。

4. 流量特征、行为检测

原理:不看 IP 和域名,专门分析协议特征(如 HTTP Host 头、TLS 握手时序、JA3/JA4 指纹,甚至数据包大小和持续时间)。

过程:当大量用户用同一个 IP 访问特定服务,或者特征高度疑似翻墙软件,直接封禁。

解决方案:纯网络层基本无解,需依赖复杂的应用层流量伪装。

封禁方式 防火墙识别依据 ECH 能否绕过 DoH 能否绕过
DNS 污染 DNS 查询域名 不相关 可以
IP 封禁 目标 IP 地址 不能 不能
SNI 检测 TLS 握手明文 SNI 可以 不相关
DPI 流量特征 / JA3 数据包特征 不能 不能

核心武器库——DoH 与 ECH 解析

现代 DNS 加密协议大比拼

协议 底层传输 加密方式 默认端口 RFC 特点
DNS UDP/TCP 明文 53 1035 原始,易窃听劫持
DoT TCP TLS TCP 853 7858 DNS 直接套 TLS,端口明显,易被封
DoH TCP HTTPS(HTTP+TLS) TCP 443 8484 伪装成网页 HTTPS,开销大
DoQ UDP QUIC (内置 TLS1.3) UDP 853 9250 UDP + 加密,无队头阻塞,性能最好

核心问答:

Q:加密 DNS 能防止域名污染吗?

A:只能保护【你 ↔ DNS 服务器】这一段不被中间人篡改。如果上游 DNS 本身就被污染了,加密也没用。

Q:哪个最难被防火墙拦截?

A:DoH。因为它走 TCP 443 端口,流量特征和普通浏览网页一模一样,防火墙很难将其从正常业务流量中剥离。

DoH(DNS over HTTPS)

中间人不能直接读到 DoH 报文里的查询域名;但依然有各种途径识别 DoH 流量,以及推断你查询的域名,只是比 DoT 更难。

DoH 本质:把 DNS 查询包装成 HTTPS 请求,走 TCP 443,HTTPS = HTTP + TLS。

DoH 加密保护了什么

TLS 加密了整个 HTTP payload: 中间人抓包看不到 HTTP 里面的内容,无法直接读取被解析的域名。 不管是 GET(域名放在 URL)还是 POST(DNS 二进制包放 body),全部被 TLS 加密。

中间人能看到什么
  1. 你的客户端 IP
  2. 目标 IP:DoH 服务器的 IP
  3. 目标端口:TCP 443(标准 HTTPS 端口,和普通网页一模一样)
  4. TLS 握手 SNI:这里 SNI 是DoH 服务本身的域名,不是你要解析的目标域名

ECH (Encrypted Client Hello):终结 SNI 明文时代

ECH 是 TLS 1.3 的扩展标准(RFC9849),用来加密 TLS 握手一开始的 ClientHello 消息,解决传统 HTTPS 里SNI 明文泄露域名的问题。

原来的痛点

普通 HTTPS TLS 握手: 浏览器发 ClientHello,里面明文 SNI,告诉服务器:我要访问 x.com。 运营商 / 防火墙抓包直接看到这个 SNI,就算后面流量全部 TLS 加密,中间人一眼知道你访问哪个域名。

ECH 核心原理:拆成两层 ClientHello

  1. ClientHelloInner(内层,加密) 里面放真实 SNI(目标网站域名)、TLS 版本、加密套件等全部真实握手信息,用网站 CDN 发布的 ECH 公钥(HPKE 混合公钥加密)加密。
  2. ClientHelloOuter(外层,明文,中间人能看到) 外层是一个伪装的正常握手,外层 SNI 是 CDN 的公共域名(比如cloudflare-ech.com),不是你真正访问的网站; 同时把加密好的 Inner 包,塞进一个encrypted_client_hello扩展字段发给 CDN 边缘服务器。
完整流程
  1. 浏览器先用 DoH(推荐)查询网站的 DNS HTTPS 记录,拿到网站公布的 ECH 公钥配置;

关键点:ECH 的公钥要通过 DNS 获取,如果 DNS 被污染 / 劫持,拿到假 ECH 配置,ECH 直接失效,所以 ECH通常搭配 DoH 一起用。

  1. 浏览器构造内外两层 ClientHello,内层用拿到的公钥加密;

  2. 发给 CDN 边缘服务器;

  3. CDN 边缘服务器持有对应的私钥,解密拿到内层 ClientHello,读取真实 SNI,再转发请求到后端网站;

  4. 建立 TLS 连接,正常传输网页内容。

中间人抓包只能看到:你连接到 CDN 的 IP,外层 SNI 是cloudflare-ech.com,看不到你真正访问的网站域名。同一个 CDN 下成千上万个网站,ECH 握手看起来全部一模一样,无法区分。

ECH + DoH 的组合

  • DoH:保护 DNS 查询,拿到真实域名解析 IP,同时安全拿到网站 ECH 公钥,防止 DNS 污染篡改 ECH 配置;
  • ECH:保护后续 HTTPS 握手,隐藏 SNI,不让中间人从握手看到真实域名。

DoH 负责安全地获取真实 IP 和 ECH 公钥(防污染);ECH 负责加密后续的 TLS 握手(防 SNI 探测)。

高阶玩法——自建智能 DoH 调度中心

自己搭建DOH服务器,修改 DNS 应答,主动注入、补全 HTTPS (ECH) 记录等等。

使用ECH可能遇到的问题

1.没有配置HTTPS记录,导致ECH未开启。

很多 CF 托管网站,服务器支持 ECH,但 DNS没有 HTTPS 记录。

ECH 想要在浏览器正常启用,有两个必要条件:

  1. 浏览器拿到 ECH 公钥:公钥承载在 DNS 的 HTTPS 资源记录(HTTPS RR,RFC9460) 里面;
  2. TLS 服务端(CDN 边缘节点)持有对应的 ECH 私钥,能解密客户端发过来加密后的内层 ClientHello。

Cloudflare 所有边缘节点,默认全部部署同一套全局 ECH 公私钥对。 私钥存在 CF 的边缘服务器上;公钥是公开的。 但是!网站域名所有者,可以选择要不要在自己域名的 DNS 记录里,发布这条 HTTPS RR(携带 ECH 公钥)。 很多接入 CF 的网站,服务器侧具备解密 ECH 的能力,但是域名 DNS 没有写 HTTPS 记录 → 浏览器拿不到公钥,直接放弃 ECH,降级普通 TLS 握手(明文 SNI)。

2.Chromium内核浏览器CNAME 会导致 ECH 失效

正常DNS标准行为:

cdn.example.com CNAME 指向 example.b.cdn.cloudflare.net

  • 你查询 cdn.example.com
  • 原始 DNS 返回 CNAME,指向 CF 二级域名,A 记录是 CF 节点 IP
  • HTTPS 记录写在example.b.cdn.cloudflare.net,而不是cdn.example.com

获取的A记录和HTTPS记录都是CNAME之后的。

Chromium(Chrome/Edge)浏览器的 ECH 规则:

HTTPS 记录 和 A 记录,必须属于同一个域名;如果域名存在 CNAME 别名解析,浏览器直接放弃 ECH。

示例: cdn.example.com CNAME 指向 example.b.cdn.cloudflare.net

  • 你查询的域名 cdn.example.com
  • 最终 A 记录来自别名目标 example.b.cdn.cloudflare.net
  • 所以 A 记录归属是 example.b.cdn.cloudflare.net
  • 但 HTTPS RR 是挂在原始查询名 cdn.example.com

Chromium 旧 ECH 逻辑判定:A 记录的所有者 和 HTTPS 记录所有者不一致 → 放弃 ECH。

核心功能

无中生有(补充 HTTPS 记录): 很多网站在 CF 有解密能力,但站长没配 DNS。DoH 识别到 CF 托管域名后,主动注入 CF 的全局 ECH 公钥,强行“唤醒”浏览器的 ECH 功能。

拍平 CNAME(解决浏览器兼容坑): Chromium 规定 A 记录和 HTTPS 记录必须同属一个域名。遇到 CNAME 时,智能 DoH 会直接将 CNAME 链拍平,返回最终 IP 和记录,绕过浏览器的严苛限制。

自动探测更新 ECH 公钥: 针对 Meta (Instagram 等) 不公开 ECH 公钥的情况,探测机主动发起握手抓取公钥,并动态注入到 DNS 应答中。

CDN 优选 IP 池(真·ECH 探活): 抛弃传统的 TCP 测速,探测机每半小时进行“真实 ECH 握手 + HTTP 200”连通性测试。连续 12 次成功且低延迟的 IP 才会被下发。

剔除“套餐隔离”IP: 过滤掉那些只允许 CF 企业版客户访问的专属节点 IP,防止普通网站出现图片/资源 403 错误。

HTTP/3 智能开关: 国内 UDP 丢包严重。探测机确认某节点 QUIC 稳定连通后,才会在 HTTPS 记录中开启 HTTP/3 标记,否则降级 HTTP/2 保证流畅。

就近解析与并发兜底: 携带客户端网段信息进行查询,分配国内最优 CDN 节点;多上游并发查询,最快响应。

终极破局——特定敏感服务的中继路由

虽然 ECH 解决了 SNI 阻断,但如果目标 CDN IP 被封禁(或者像 ChatGPT/Grok 这样在应用层封杀中国大陆 IP),直连依然会失败。

智能分流链路

我们需要在 DoH 层面引入按需中继机制:

  • 普通出海网站: DoH 返回 CF 优选 IP —> 浏览器直接 ECH 握手 —> 正常访问。
  • 受限 AI 服务: DoH 识别到 ChatGPT 等域名,不返回 CDN IP,而是返回你自建的中继 VPS IP。

中继架构的流量链路: 浏览器 —>(ECH 加密握手)—> 中继 VPS —> Azure / 国际路由 —> CDN 边缘节点—> AI 服务

工作细节:

  1. 盲转发: 中继服务器只读取明文的外层 ECH 标签(确认是合法流量),看不到内层真实域名,不终结 TLS 握手,只做纯四层字节转发。
  2. 端到端加密: 真正的 TLS 加密通道建立在你的浏览器与最终的 CDN 节点之间。
  3. 安全加固: 中继服务器配置访问控制,仅放行携带特定外层 SNI 的 ECH 握手连接,直接拒绝普通的明文 TLS 扫描,防止被 GFW 主动探测。
  4. 降级 TCP: 限制中继链路仅支持 TCP (HTTP/2),并只返回 IPv4 地址,防止浏览器优先走 IPv6 UDP 直连 CDN 从而暴露身份。

中继服务器的生存法则(防主动探测)

中继 VPS 作为唯一暴露在 GFW 视线下的节点,绝对不能使用傻瓜式的纯四层盲转发,否则面对防火墙的主动探测活不过三天。必须在 VPS 部署具备 SNI 嗅探与回落 (Fallback) 能力的反代软件(如 Nginx Stream 或 Xray-core)。

中继节点的“两幅面孔”逻辑:

  1. SNI 嗅探识别“自己人”: 当收到 TCP 流量时,中继只读取明文的外层 ECH 标签。如果外层 SNI 匹配(例如是 cloudflare-ech.com),说明这是浏览器的合法 ECH 流量。此时不终结 TLS,直接将字节流转发给背后的 CDN 节点,实现端到端加密闭环。
  2. 回落伪装对付“审查员”: 如果外层 SNI 不匹配,或者收到的是乱码探测包,说明这是 GFW 的主动探测。此时中继立刻触发 Fallback,将流量路由到 VPS 本地搭建的一个极其正常的伪装网站(例如一个挂有合法证书的静态博客)。GFW 扫描器只会看到一个普通博客,从而认定该 IP 安全。
  3. 极简攻击面: 中继服务器仅开放 443 和 SSH 端口,转发目标严格限制为目标 CDN 的 IP 段,防止被恶意利用。

架构能力边界——死局

这套“无客户端”架构虽然惊艳,但它存在一个不可逾越的物理边界:当目标 CDN 官方指定的 ECH 公共域名(外层 SNI)本身被防火墙拉黑时,纯网络层中继将彻底失效。 典型的例子就是 Google。

防火墙的“一刀切”:直接阻断 ECH 协议特征

在某些敏感时期或特定地区的运营商网络中,GFW 根本不再费心去鉴别你要访问谁。只要其深度包检测(DPI)系统识别到 TLS 握手数据包中包含 ECH 扩展特征(如 Type 65037 字段),就会采取“宁可错杀一千”的策略,直接将数据包丢弃(Drop)。面对这种针对协议本身的物理“拔网线”,纯四层转发没有任何反抗余地。

公共域名封锁:为什么 CF 能活,而 Google 必死?

即使防火墙没有全局封杀 ECH 协议,而是通过黑名单拦截 ECH 的公共域名(外层明文 SNI),不同的 CDN 也会面临截然不同的命运。这本质上是一场关于“误杀成本”的博弈:

  • Cloudflare(自带免死金牌,极难被彻底阻断): CF 的 ECH 外层域名通常是 cloudflare-ech.com。作为全球最大的 CDN 巨头,CF 承载了海量的国内出海企业、跨境电商、外贸网站,甚至部分国内站点的海外加速业务。如果 GFW 彻底将 CF 的公共域名或 Anycast IP 段加入黑名单,会导致极其严重的连带经济损失(巨大的误杀成本)。正因为这种“大到不能封”的护城河,依托 CF 的 ECH 架构往往能在夹缝中长期稳定生存。
  • Google(零成本击杀,绝对的无解死局): 与 CF 截然不同,Google 使用的是纯自家的骨干网和 CDN,其 ECH 公共域名(如 echo.google.com)和 IP 节点几乎完全只服务于 YouTube、Search 等谷歌系产品。由于这些业务在中国大陆原本就不合法且被全面封杀,GFW 阻断 Google 的 ECH 域名没有任何连带成本(Zero Collateral Damage)。因此,试图用纯中继架构访问 Google,会在国境线上被毫无顾忌地精准击落。