Skip to content

如何使用伪造 SNI 的功能

SeaHOH edited this page Mar 29, 2021 · 11 revisions
  • 什么是 SNI?

    https://zh.wikipedia.org/wiki/服务器名称指示

  • 被封锁网站的 SNI 和 GFW 有什么关系?

    https://zh.wikipedia.org/wiki/防火長城#TCP连接重置

  • 如何绕过 GFW 对 SNI 的封锁?

    修改 TLS 连接原本的 SNI 为其它未封锁的名称,或者设置不发送 SNI 扩展。

  • 伪造 SNI 的方法有何限制?

    排除以下情况才适用伪造 SNI 以绕过封锁的方法:

    • DNS 污染,可以解决

      SNI 的封锁通常伴随着 DNS 污染,可以使用 GotoX 内置的反污染功能,也可以在主配置中设置为优先使用你选择的其它反 DNS 污染的工具 (如 Pcap_DNSProxy、DNSCrypt),以确保 DNS 结果无污染,此时通过 GotoX 的 forward/direct 动作访问,可以在日志中看到连接使用的 IP 地址。

    • IP 封锁,无法解决

      Ping 无污染解析到的 IP,如没有回应则属于 IP 封锁。

    • 网站服务器有严格的 SNI 安全设置,无法解决

      通常表现为证书无法验证,伪造 SNI 连接失败;还可能直接返回错误页面。

  • 在 GotoX 中该如何设置和修改 SNI?

    具体配置位置为 config/ActionFilter.ini仅 fakecert 规则适用,其作用范围也仅限于 forward/direct 动作,请不要同时配置优先匹配这两个动作之外的其它规则

    写法为:域名 = Host@SNI,可参考默认配置示例

    • Host 是用于替代 Host 头域来验证证书是否匹配

    • SNI 是用于设置 SNI 名称

    • 可以省略 Host@ 直接填写 SNI 名称

    • Host 为 same,以 SNI 名称替代 Host 头域来验证证书是否匹配

    • Host 为 none,不验证 Host 头域是否匹配证书

    • SNI 为 none,不发送 SNI

    • SNI 为 *,随机生成 SNI 名称

    • * 作为通配符用于 SNI,限定 SNI 名称部分随机

    • *{n} 作为通配符用于 SNI,同上,可指定随机部分长度为数字 n

    部分网站因为 IPv4 IP 被封锁,需配合 IPv6 IP 使用(如果有且未被封锁),可以在 forward/direct 规则中用 @v6 限定。

  • 如何判断网站是否被 GFW 封锁 SNI,以及如何选择伪造的 SNI 名称?

    1. 在浏览器中新建标签页

    2. 按下 F12 打开开发者工具,选择 网络/network 面板

    3. 在地址栏中输入转到使用 HTTPS 的目标网址,等待页面加载完成,面板日志会记录失败的请求

    4. 点击日志条目查看,如果 消息头/Headers 中没有 响应头/Response Header 这个域名可能就是被 SNI 封锁

    5. (如已排除 DNS 污染和 IP 封锁可跳过此步骤)Ping 上一步得到的域名,如果有回应,基本可以肯定就是 SNI 封锁,否则就是 DNS 污染或 IP 封锁

    6. 可以先尝试不发送 SNI(配置方法见上方),服务器将发送默认证书,如果证书匹配则连接成功

    7. 如果上一步失败,尝试限定使用 IPv6 连接(如果有且未被封锁)

    8. 如果上一步失败,尝试修改原域名的次级域名作为 SNI,如:
      .palemoon.org = img.palemoon.org

    9. 或者修改成同一个服务器的其它未封锁域名,如:
      www.instagram.com = graph.cdninstagram.com

    10. 也可以尝试任意其它你想要使用的 SNI 名称

    11. 如果被封锁网站与其它网站共用 IP(如免费 CDN),则必须发送 SNI,且保留主域名不变

  • 使用 CNAME(如果有)作为 SNI

    有人发现了华点:如果本机 DNS 没有做反污染措施,那么以下操作多半是不会返回任何 CNAME 的。附上发现者提供的网页工具替代 https://www.diggui.com/

    1. 使用 nsloookup 或 dig 查询主机名 Host 的 CNAME 记录,这里以 nsloookup 为例:

      user>nsloookup
      Server/服务器: ...
      Default server/默认服务器: ...
      Address: ...
      > set q=cname
    2. 当 CNAME 与 SNI 同域,以 github 上传下载文件的域名为例:

      > github-production-upload-manifest-file-ffffff.s3.amazonaws.com
      Server/服务器: ...
      Default server/默认服务器: ...
      
      Non-authoritative answer/非权威应答:
      github-production-upload-manifest-file-ffffff.s3.amazonaws.com  canonical name = s3-1-w.amazonaws.com
      > github-production-release-asset-ffffff.s3.amazonaws.com
      Server/服务器: ...
      Default server/默认服务器: ...
      
      Non-authoritative answer/非权威应答:
      github-production-release-asset-ffffff.s3.amazonaws.com  canonical name = s3-1-w.amazonaws.com

      CNAME 都是同一个 s3-1-w.amazonaws.com,可以用正则匹配主机名简写成一条规则:
      @^github.+s3.amazonaws.com$ = s3-1-w.amazonaws.com

    3. 当 CNAME 与 SNI 不同域,以 nytimes 中文网域名为例:

      > cn.nytimes.com
      Server/服务器: ...
      Default server/默认服务器: ...
      
      Non-authoritative answer/非权威应答:
      cn.nytimes.com  canonical name = d1f1eryiqyjs0r.cloudfront.net

      由于 d1f1eryiqyjs0r.cloudfront.netcn.nytimes.com 不同域,无法通过证书验证,需要使用 same 关键字来配置:
      cn.nytimes.com = same@d1f1eryiqyjs0r.cloudfront.net

    4. 根据环境不同,查询到的 CNAME 也不一定相同,根据实际查询到的值设置即可