如何绕过网站备案拦截

最近因为 obsidian 的文件同步的插件 self-hosted LiveSync 升级后移动端只能使用 https 来进行文件同步,所以就使用腾讯云的 DNSPod 和免费证书做了 https 的域名服务,由于域名备案未通过所以域名无法正常访问

拦截机制

HTTP 拦截

http 使用了 302 重定向劫持,让重定向回包先于正常会包返回给用户,这种方法据说是传统运营商作恶的一个途径。要解决 302 劫持的问题就需要升级到 https。

HTTPS 拦截

https 增加了 SSL 加密,7 层的数据不能被篡改因此就能避免 302 劫持的问题,所以 https 的拦截就放在了下移到了 TCP 层,将特点 TCP 请求直接 RST。由于拦截的规则是未备案域名 + 大陆服务器所以要判断 一个 TCP 请求是否该被拦截,服务端就必须知道 TCP 请求对应的域名,这个域名从哪来呢?这个在 SSL 握手中的 客户端发的 ClientHello 包中,ClientHello 和服务端返回的 ServerHello 是用来做加密前客户端与服务端的勾兑,由于服务端并不知道要使用哪个证书进行加密,所以 ClientHello 中就必须包含明文的 SNI(即域名)作为勾兑的必要内容。所以服务端可以在收到 ClientHello 直接进行 TCP 的 RST。

如何绕过拦截·

按以上拦截的条件:未备案域名 + 大陆服务器就有以下思路

境外服务器

使用境外的服务器,就不会被拦截。这其实也不算绕过,因此云厂商是允许未备案域名在境外服务器上正常访问的

ECH

拦截服务必须知道域名才能判断是否备案,那如果拦截服务无法在 ClientHello 中拿到域名是不是也能绕过拦截呢?cloudflare 的 ECH 的方法也许可以。ECH 全名 Encrypted Client Hello 就是对 ClientHello 进行加密。简单讲就是这个协议将 ClientHello 分为内外层,外层依然需要指定一个明文的 SNI(统一为 cloudflare-ech.com),内层真实请求的域名就被加密了,所以理论上就只有客户端、cloudflare、服务端的七层服务知道请求的域名,因此服务端的拦截服务就无法拦截了

由于 ECH 是为解决互联网访问隐私而不是绕过备案拦截出现,ECH 在这里有两个问题:

  1. 目前仅 cloudflare 支持 ECH,这里的机器都是境外的,所以一开始就不存在备案拦截的问题
  2. 假如国内支持 ECH 呢?国内一旦支持 ECH,现有的拦截方法自然就有了缺陷需要迭代。最简单的方法就是将 ECH 外层的统一域名都拦截了

换端口(最终方案)

说了那么多,除了正常申请备案和用境外服务器,就没有其他方法了吗?
有的,服务端的拦截服务经过测试,并没有监听全部端口。若将 https 从 443 换成 441 之类端口进行监听。客户端访问从 https://example.com 换成 https://example.com:441 就能正常访问。
当然这样作为一个对外开放的网站这不可接受,但如果作为自己私有的话,完全足够

另外:http 用的 302 劫持在七层,它不关心端口,所以这个方法对 http 无效

其他

据说还可以使用 CDN,将其回源指向大陆的服务。其原理大概是直接申请一个已备案的 CDN 域名或国外不需要备案的 CDN 减少了备案的麻烦。我没尝试过不知道行不行。
能想到的一个缺点是:由于 CDN 一般是 HTTP1.1 短连接回源,如果是动态请求的话,访问延迟会很大

总结

除了自用域名可以使用非 443 端口避免备案外,域名要想要支持对外访问除了用境外域名就是老老实实做域名备案了