都市霓虹中的初音未来

伪造 SNI 突破审查

我国智慧勤劳的劳动人民前段时间搞出来一个很新的科学上网方式——伪造 SNI。实现方法十分令人震惊:只需要给浏览器启动时加上一段参数,就可以免服务器访问谷歌、X、维基百科等等站点。例如:

1
google-chrome-stable --host-rules="MAP *google* google.cn,MAP *youtube.com google.cn,MAP *.ggpht.com google.cn,MAP i.ytimg.com google.cn," --host-resolver-rules="MAP google.cn 82.118.16.109," --test-type --ignore-certificate-errors

用这段命令行启动 Chrome,就可以直接访问 google.comyoutube.com,速度还挺快(虽然 YouTube 不能播放视频)。

要知道,上一次我们能做到这一点,大概是 10 年前;GFW 还只使用 DNS 污染的时候,可以通过设置一个加密 DNS,实现自由访问。大规模的 IP 封禁现在已经成了 GFW 封禁手段的主流,特别是 HTTPS 普及、无法过滤页面上的内容之后,无需一部境外服务器的方法就基本绝种了。

当然,部分站点(例如 GitHub、LINUX DO)依然可以通过 DNS 设置解决访问问题,因为它们都没有被完全封禁,仅仅使用了 DNS 污染和封禁部分 Anycast IP 的方式阻碍连接。

那这到底是怎么回事?和 1 月 1 日发生的小规模“漏风”事件是否有关?词元也来看看。

🙅‍♂️ 免责申明

本文采用了一些来自网络的资料,因为范围实在太广,词元又没有记录来源的好习惯,无法一一列出,若您感觉某一段内容很熟悉,不必怀疑,大概就是您读或写过它。如果您比较介意词元的行为,敬请邮件告知,词元将添加对您的内容的引用。

本文所有内容与突破中华人民共和国国家防火长城无关,只适用于突破类似 OpenGFW 等第三方防火长城实现,也请读者承担自己的责任,勿以 GFW 作为实验对象,谢谢。

🔧 实现方法

首先我们先来试一试效果。如果您是 Linux 用户,可以直接使用上文所述的那个命令启动 Chrome,然后看看是不是可以正常访问 Google 了;如果您是 Windows 用户,请修改 Chrome 快捷方式,将那段参数添加在原本的命令之后。

以上参数只能访问 Google 和 YouTube,使用不良林提供的工具(先抓取,再处理),我们可以获取一套完整的参数,能访问主要的被墙网站,但是一小部分还是无法访问。

访问网页之后,您会发现,似乎所有的功能都能正常使用,从登录到注册再到……等等,YouTube 无法播放视频,Netflix 之类的流媒体也是。

这段神奇的参数到底是干什么的呢?能不能全系统使用?有什么可以改进的?

⚙️ 原理

要知道刚刚到底是怎么神奇地越过了 GFW 的限制,首先要简单地理解一下 GFW(已知的一种)拦截方法。

我们在浏览器端发出的请求,如果是 HTTPS 的,在发送前,会对其进行 TLS 封装,将其中的内容进行加密,也就是 HTTPS 中那个 S 代表的安全性。这样做可以保证中间人无法获知其中的内容。为了标识访问的域名,在包的未加密外层会添加服务器 IP 地址和 SNI 属性(Server Name Indication)等,用于在服务器端 TLS 握手时确认访问目标。

在我们的数据包经过 GFW 时,GFW 会查看 SNI 属性,如果命中了它的封禁列表,就会丢弃数据包,您也就无法访问这个网站了。

这里,我们就有了可乘之机。既然 GFW 通过 SNI 检测数据包,那我们将 SNI 设置为一个不存在(CYFM)或者未被封禁的域名(g.cn),不就可以了吗?真棒。

但这里还有一个问题。数据包信息是肯定带有 IP 的,有可能你访问的 IP 本身就被封禁了,那也会被 GFW 轻松拦截。那我们就要动一点小手脚,把 SNI 强制映射到这个网站的服务器(Google 这种大站往往不止一个 IP,而且分布在全球),这样 SNI 也没有敏感信息,IP 也还未封禁,当然就可以通过了。

这样做是有后果的:

  • 其一,服务端 IP 比较多的情况下,只需要映射 IP 即可(SNI 用 CYFM 糊过去);但是如果服务器 IP 有限,全被封了,就必须要有一个没有被封、可达服务器的域名。
  • 其二,除非服务器不验证 SNI,如果 SNI 使用的域名不符合服务器,服务器会拒绝访问,可能返回一个“连上了,但是内容我不给你”的错误。
  • 其三,就算服务器确实不主动验证 SNI,其返回的 TLS 证书与浏览器端的 SNI 也对不上,所以会显示“不安全”。
  • 其四,个别大流量服务器(如 YouTube)不接受任何错误的 SNI:对于骇客来说,这可是刷流量的好机会。
  • 其五,伪造 SNI 是 Chromium 的特性,所以系统级免代理不可能(甚至连 Firefox 也是不行的)。

其中,第二、三点在一些站点上不存在(例如 Google),因为我们使用 g.cn 这一未被墙域名作为 SNI,它与 google.com 共享 TLS 证书,就能正常访问。

📺 流媒体

上面说到,除了个别流媒体平台,都可以解决问题。如果就是想解决一下流媒体的问题呢?

那就请您看不良林这个比本文更加详尽的视频吧,最后一段对这件事有详细的介绍。

Banner