匿名 CDN 流量中继
CDN 实现流量中继
上篇博客中介绍了一种利用 CDN 实现网络流量中继的方案: Self-host Relay Service with CDN。我们将 TCP 和 UDP 流量封装在 Websocket 通道中,通过 CDN 转发至中继服务器。
使用 CDN 转发流量使得正在侦听的第三方无法确定中继服务器的真实地址,从而加大了审查者封锁的难度。这样的安全特性激励了越来越多的用户使用类似的方法绕过互联网审查。例如,Trojan 项目的文档 就推荐使用 Websocket 进行 CDN 转发。主流代理软件也纷纷添加了对 Websocket 通道的支持。
使用 CDN 隐藏服务地址的做法日益流行,迫使审查机构寻找新的方法维持封禁。例如,俄罗斯要求 CDN 服务商禁止“域前置”功能1。韩国广播通信审议委员会使用 SNI 嗅探封禁网站2。中国大陆和俄罗斯电信运营商全面封锁 ESNI3。
这篇博客将介绍围绕 CDN 进行的封禁与反封禁博弈。虽然日趋严格的封禁听上去令人失望,但正是不断升级的封禁策略和不断变化的反封禁手段共同作用,才促进了互联网向着更安全、私密的方向蓬勃发展。
CDN 如何处理 HTTPS 请求
CDN 服务商通常会在全球部署多个数据中心,每个数据中心都有多个节点。用户的请求会首先到达最近的节点,然后由节点转发至下一个节点,直至请求到达目标服务器。这样的转发过程称为“回源”。
CDN 服务商通常会根据用户的地理位置、网络质量等信息,选择最优的节点进行回源。用户向权威 DNS 发起询问,权威 DNS 会返回最优的节点的 IP 地址。如图中 ① 和 ② 所示。
获得最优节点的 IP 地址后,用户向节点发起 HTTPS 请求。在这一步中,用户与节点之间建立了 TLS 连接。用户在 TLS 握手阶段会发送 SNI 扩展。节点会根据 SNI 的值,选择正确的 TLS 证书进行回复。如图中 ③ 所示。
TLS 连接建立后,节点根据 HTTP 请求的 Host 头部,将请求内容转发到源服务器。如图中 ④ 所示。
服务器名称指示(SNI)
许多 Web 服务器会托管一个以上的网站,并且可能每个网站都有自己的 TLS 证书。如果服务器向客户端显示错误的证书,客户端将无法安全连接到所需网站,从而导致出现“您的连接非私密”错误。
SNI 通过标示客户端正在尝试访问哪个网站来解决此问题。SNI 扩展是 TLS 握手阶段的一部分,位于 ClientHello 消息中。CDN 节点根据 SNI 的值,选择正确的 TLS 证书进行回复。
矛盾的是,只有在使用 SNI 成功完成 TLS 握手后,才能进行加密。SNI 是在 TLS 握手开始时发送的,不会被加密。结果,任何监视客户端和服务器之间连接的攻击者都可以读取握手的 SNI 部分,以此确定客户端正在与哪个网站建立连接。韩国广播通信审议委员会正是通过这种方式,监视了用户的上网行为。
域前置
域前置是一种基于 CDN 隐藏连接真实地址来规避审查的技术。著名的加密聊天软件 Telegram 就曾经利用亚马逊 CDN 进行域前置,逃避俄罗斯的封锁。
此技术的原理为在不同通信层使用不同的域名。在明文的 DNS 请求和 TLS 服务器名称指示(SNI)中使用无害的域名来初始化连接、公布给审查者,而实际要连接的“敏感”域名仅在建立加密的 HTTPS 连接后发出,使其不以明文暴露给网络审查者。域前置使用户能通过 HTTPS 连接到被屏蔽的服务,而表面上像在与另一个完全不同的站点通信。
CDN 为何不根据 TLS 中的 SNI 标志选择源服务器,而是依照 HTTP 请求头的 Host 值进行转发呢?
进行 TLS 加密通信不必须要求证书合法。例如用户在收到“您的连接非私密”提醒后,点击“仍要访问”,此时浏览器和服务器之间仍然可以利用过期或错误的证书进行加密通信。部分旧版本浏览器甚至不会发送 SNI。基于这样的观察,CDN 服务商一般只以 HTTP 请求头部的 Host 值作为转发的依据。
审查者通常很难区分被伪装流量与合法流量的特点,迫使审查者选择放行所有看似无害的流量,或者选择彻底封锁此域的流量。而彻底封锁可能带来显著的附加损害。
但审查者可以强制 CDN 服务商禁止域前置功能。例如,Google、Cloudflare 等厂商已经修改了转发逻辑。现在,大多数 CDN 服务商会在进行转发前验证 SNI 与 Host 是否相同。如果两者不一致,则拒绝回源。
加密服务器名称指示(ESNI)
正如 Cloudflare 创始人所言,明文传递的 SNI 是整个网络加密体系中的最后缝隙。填补这个缝隙有助于提升整个互联网的私密性。顾名思义,ESNI 通过加密 TLS 握手的服务器名称指示(SNI)部分来实现其目的。
由于客户端问候消息是在客户端和服务器协商 TLS 加密密钥之前发送的,因此 ESNI 加密密钥必须以其他方式进行传输。Cloudflare 给出的解决方案是:在域名的 DNS 记录中添加一个公钥。这样,当客户端通过 DNS 解析查找服务器 IP 时,就能同时获得服务器的公钥。然后,客户端使用这个公钥来加密 SNI 记录,以便只有正确的服务器才能解密它。
当然,如果攻击者通过 DNS 抢答的方式篡改了 DNS 解析的返回值,替换了其中的公钥,ESNI 仍然不能确保连接的私密性。因此,Cloudflare 希望所有用户使用 DNS-over-HTTPS 保障 DNS 的私密性。
ESNI 保护了 HTTPS 的私密性。通过 HTTPS 发出的 DNS 请求又保护了 ESNI 的正确性。这样就形成了网络加密体系的完整闭环。审查者无法通过任何方式监视用户上网的行为(访问的网页地址、传递的数据内容等等)。似乎自由取得了最终胜利。在 2020 年的 DEF CON 大会上,大家津津乐道地讨论着域名隐藏技术(Domain Hiding)。
加密互联网的大厦
得益于“全过程加密”,所谓“域名隐藏技术”就是没有技术——它不用做任何事!加密互联网的大厦已经落成,所剩的只是一些装饰工作。唔,不过,正如图中所示,它的美丽而晴朗的天空却被两朵乌云笼罩了——那片 CDN 的云朵周围还飘着两朵红色的乌云。
2022 年的今天,对于 CDN 服务商而言,用户的请求数据仍然是明文的。用户发送的 HTTPS 请求在边缘节点处被解密,CDN 服务商可以(且必须)了解请求的具体细节。例如,使用 HTTP 头部的 Host 信息确定源服务器地址,或针对不同的 URL 实行不同的缓存策略。如果审查者控制了 CDN 服务商,那么我们将直接倒退回 HTTP 时代!即使我们通过其它方式给 HTTP 载荷加密,不过只是回到了起点,CDN 并不能提供任何额外的保护。
事实就是如此的残酷。我们几乎可以确信审查者早已牢牢控制了 CDN 服务商。中心化网络结构注定不可能逃避审查。
这篇博客开头提到:CDN 服务商通常会在全球部署多个数据中心,每个数据中心都有多个节点。用户的请求会首先到达最近的节点,然后由节点转发至下一个节点,直至请求到达目标服务器。CDN 的云朵包裹着数万个节点构成的“边缘网络”,是的,审查者可以强硬地控制这些网络。那么如果——我们把“边缘网络”替换成一个由数亿设备构成的去中心化网络会怎样?网络中的每个节点都参与到数据传输中,你我都是火炬的传递者,而审查者无法控制整个网络。如果我们把信息写在一个不可篡改的公开账本上又会怎样?密码学已经能够保障传输的隐秘性。它的下一个目标是保护数据本身。
同志们,我们正处于革命前夜。眼下,有志之士纷纷投身到下一代 Web 技术的研发中去。乌云的背后是漫天繁星。到那时,封锁与突围的博弈又会是怎样的精彩,我已经迫不及待地想看到了。
Footnotes
-
Google 关闭域前置,影响反审查工具. Solidot. ↩
-
South Korea is Censoring the Internet by Snooping on SNI Traffic. Bleeping Computer. 2019 ↩
-
Possible blocking of Encrypted SNI extension in China. iyouport. ↩
CDN 实现流量中继
© LICENSED UNDER CC BY-NC-SA 4.0