域前置 domain fronting

本文教你怎么用域前置(domain fronting)访问被封锁的网站。首先理解什么是域前置。

 

什么是域前置


现在的网站通常使用 HTTPS 协议,数据在传输过程中是经过加密的;域前置也是基于 HTTPS。这个过程分为两个阶段。

  1. 连接到服务器
  2. 发送请求

在第一阶段,浏览器或者其他用户端软件使用 TLS 的一个扩展协议,服务器名称指示,即 SNI 连接服务器的时候会包含要访问的网站域名。问题就出在这里,发送的这个域名是明文的,如果这个域名不被允许访问,防火墙就会拦截。 规避的方法也很容易,只要连接时发送不被封锁的域名即可。

在连接之后,发送的数据都是经过加密的。所以假设我们要访问 Google 搜索,浏览器将发送类似以下信息:

CONNECT www.google.com
Host: www.google.com

第一行连接 www.google.com 的服务器,因为这时域名没有经过加密,所以会被防火墙拦截。我们把域名改成防火墙不会拦截的域名即可,比如 g.cn

 

利用域前置访问 Google


要能通过域前置访问 Google,需满足三个条件:

  • 可以连接的 IP
  • 不会被拦截的域名
  • 支持修改连接域名的软件

第一个条件其实很容易满足,虽然 Google 网站官方的 IP 都无法连接,但网络上有很多提供中转的 IP 可使用,只要稍微搜索一下就能找到。请看怎么查找 Google IP

第二个条件:Google 有很多域名,比如 g.cn 就不会被拦截,所以我们就用它。

能够满足第三个条件的软件不多,但采用 Chromium 内核的浏览器(如 Google 浏览器,微软的 Edge 浏览器等)都可以使用。

这里以 Google 浏览器为例,使用的是韩国 IP 1.11.211.168:12243,由于这不是 Google 的官方 IP,所以可能过段时间后不可使用。

在启动 Google 浏览器的时候加入以下参数,或者 Windows 系统下右击浏览器快捷方式选择属性,在目标栏里添加:

--host-rules="MAP *.google.com g.cn:12243, MAP *.gstatic.com g.cn:12243, MAP *.googleapis.com g.cn:12243" --host-resolver-rules="MAP g.cn 1.11.211.168"

如果是通过命令行启动:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --host-rules="MAP *.google.com g.cn:12243, MAP *.gstatic.com g.cn:12243, MAP *.googleapis.com g.cn:12243" --host-resolver-rules="MAP g.cn 1.11.211.168"

打开之后访问 https://www.google.com/ncr,记得一定要 https:// 开头。

利用 domain fronting 打开 google 网站

 

利用域前置访问 Twitter


同样原理,要想利用域前置访问 twitter,也得满足以上三个条件,这里就不再多讲了。

 

利用域前置访问所有网站


如果你有国外服务器,你可以搭建自己的中转服务。其实就是配置 nginx,大概是这样:

# nginx 的配置文件
# 其他配置项

http {
  # 其他配置项

  server {
    listen 8443 ssl http2;
    server_name example.org;
    ssl_certificate     /etc/nginx/example.crt;
    ssl_certificate_key /etc/nginx/example.key;
    resolver 8.8.8.8;
    resolver_timeout 3s;
    proxy_buffers 256 4k;
    proxy_max_temp_file_size 0k;
    proxy_ssl_server_name on;
    location / {
        if ($host = example.org){
          return 200 "Hello, world!";
        }
        proxy_pass https://$host;
        proxy_ssl_name $host;
        proxy_set_header Host $host;
    }
  }
}

然后生成自签名证书,根据提示填入信息,除了在 Common name 填入 example.org 外,其他都默认:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/example.key -out /etc/nginx/example.crt

最后给浏览器添加相应的参数,假设你服务器 IP 是 203.0.113.2

--host-rules="MAP * example.org:8443" --host-resolver-rules="MAP example.org 203.0.113.2"

由于你用的是自己签发的证书,所以在浏览器提示证书不被信任时直接点击信任就可以了。