摘要#
随着互联网技术的快速发展,信息传播的速度和范围大幅提升。社交媒体、博客、视频平台等新兴媒介使得个人和团体能够轻松地分享观点和信息。这种信息的自由流动促进了公众参与、社会运动和民主化进程。然而,网络的开放性也带来了信息控制的挑战。许多国家和地区的政府出于维护国家安全、社会稳定和政治控制的考虑,逐渐加强了对网络内容的审查。这种审查制度通常表现为对特定网站的封锁、对社交媒体内容的监控以及对言论的限制。
本文将对两种常见的封锁技术进行原理说明,并提供检测思路:DNS 缓存投毒和SNI 阻断。此外,我们还将提供相应的 PoC(概念验证)工具,以便更方便地检测您的网络和目标域名是否受到这两种封锁方式的影响。需要注意的是,所提供的方法尚未经过广泛测试,因此在某些使用这些审查技术的国家或地区可能有效,但在其他国家或地区则可能无法正常工作。
本文不讨论绕过封锁技术的方法,也不讨论其他未被提到的封锁和审查手段。对于 DNS 缓存投毒的讨论仅限于基于 UDP 的 DNS 协议,基于 TCP 的 DNS 可以自行去实验。
本文的检测方法不需要实验者部署额外的服务器,是一种原理检测的方法。
名词解释#
域名(Domain Name): 域名是一个易于记忆的字符串,用于标识互联网上的一个特定位置或资源。域名的存在是为了解决 IP 地址不便于记忆的问题。例如:www.fubao.dev 就是一个域名。
DNS(Domain Name System):域名系统。目标域名的访问实际上最终使用的依然是 IP,这个系统相当于一个号码簿,通过姓名可以查到电话号码,通过域名系统可以通过域名查询到 IP 地址,例如 www.fubao.dev 对应的 IP 地址为 34.41.105.151
SNI(Server Name Indication):服务器名称指示(SNI)是 TLS 协议的一个扩展。在握手过程开始时,客户端会告知所连接的服务器目标主机名称。这使得服务器能够在同一 IP 地址和 TCP 端口上呈现多个证书,从而支持在同一 IP 地址上提供多个安全(HTTPS)网站或其他基于 TLS 的服务,而无需所有站点使用相同的证书。
简单来说,一个 IP 地址可以部署多个域名。当通过 HTTPS 访问时,若需验证证书的合法性,客户端必须通过 SNI 告知服务器应提供哪个域名的证书,以确保握手过程顺利进行。虽然服务器可能只关注 HTTP 层面的 Host 信息,但为了兼容性,通常会在握手时发送 SNI 信息。
SNI 信息分为两类:一种是明文 SNI 信息,这种方式最为常见且兼容性较好;另一种是加密的 SNI(ESNI),但本文不讨论 ESNI。
DPI(Deep Packet Inspection):深度包检测技术,是一种网络数据包过滤技术,旨在分析通过检测点的数据包内容,包括其数据部分和可能的标头。该技术用于识别不符合规范的协议、病毒、垃圾邮件和入侵行为。通过预设的标准,DPI 可以决定数据包是否允许通过,或将其路由至其他目的地。此外,DPI 还可用于收集网络流量的统计数据,用于监控和定向投送广告。例如,对于一些 DPI 系统,SNI 信息和 DNS 查询的目标信息就是需要收集和关注的信息。
通常对于网络封锁技术来说,DPI 系统还需要与一些能执行具体封锁动作的服务进行交互。大型的 DPI 系统及其执行单元为了不影响正常网络,一般采用镜像流量并旁路部署的方式,通过注入特定的包达到阻止通信的目的。这种系统一般被称为包注入器。
DNS 污染:DPI 检测到对封锁域名的查询后,通过包注入器抢答 DNS 响应。因为 DPI 设备离查询方更近,注入包会先到达;对于某些先进的 DPI 及动作系统,可能还会丢弃后续到达的正确的响应包。
SNI 阻断:DPI 检测到对目标域名 HTTPS 请求中包含需要封锁域名的 SNI 信息后,注入 TCP RST 包,断掉请求方和目标的连接。对于一些专业的 DPI 系统,这个 RST 阻断包大多数都是双向的,即告诉客户端,服务端与你主动断开了连接,也告诉服务端,客户端与你主动断开了连接,保证一些简单丢弃 RST 包绕过封锁的手段不生效。
审查残留:对于某些 DPI 系统来说,基于应用层和其他层的封锁逻辑可能会发生联动。举例来说,如果你使用特定 IP 和 SNI 访问了目标网站,下次在连接此 IP 时,握手包可能会被丢弃,通常这种用于丢弃包的系统不是旁路部署;审查残留对研究一些 DPI 系统的工作方式提供了方便,也带来了一些不便,本文会提及,但不会做大面积讨论。
渔:DPI 和包注入器的常见弱点#
对于大规模数据场景下的 DPI 和包注入系统来说,吞吐量和处理能力是其重要的指标。为了在成本和效果之间做平衡,DPI 系统和包注入器通常都具有以下缺陷:
-
对目标协议栈的实现通常都是轻量的,是完整协议栈的一个最小可用子集,通常不会完全满足 RFC 实现,这是出于成本的考虑。例如,用于 TCP 的 DPI 系统并不会校验 TCP 包的 checksum 值是否合法;
-
DPI 和包注入器为旁路部署,只能看到经过他们的包,收集的信息不完整。例如,DPI 系统无法知道离目标还有多少跳,因此很容易受到欺骗。例如,如果发送刚好能够经过 DPI 和包注入器而到达不了目标的 TTL 值的包,DPI 和包注入器也会开始工作;虽然很多 DPI 和包注入器会假设和目标的跳数,但是这种假设是不能覆盖精心构造的 TTL 值的包
-
DPI 可能会重组被 TCP 等流式传输的协议的数据流,但是都存在一个等待时间的限制。
-
etc
DNS 污染的识别#
通常 DNS 污染识别的方法是和正确的结果进行对比,但是这种方法不具有通用性,由于 ECS 和 CDN 技术的存在,DNS 服务器可能会返回离请求方最近的服务器 IP 信息,以此来保证最佳的访问体验,目标服务可能会在不同的区域和国家使用不同供应商的服务,这种检测方法可能会造成大量的假阳性。
结合 DPI 系统的常见弱点,因为 DPI 系统不关心请求是否合法,我们可以构造这样一个非法的 DNS 查询,这个查询请求中告诉 DNS 服务器,我们的查询请求中包含查询结果。
正常的 DNS 查询如下图:
我们构造的非法查询,修改了如图圈出的部分:
非法查询如果未被抢答(也就是没被污染),我们看到的结果是 DNS 服务器报错:
非法查询被抢答(也就是 DNS 被污染),我们看到的响应是正常的的响应结果:
PoC: dns_pollution.py
使用示例:
SNI 阻断的检测#
SNI 阻断的检测我们要排除 DNS 污染的影响。由于 DPI 系统通常使用的信息有限,我们使用一些确保一定可以访问的出境 IP 地址,发送带 SNI 的请求,看是否收到 RST 包即可,无需完整完成 HTTPS 握手。
PoC:sni_block.py
使用示例:
总结#
根据以上思路,检测的方法还有很多变种,祝大家玩得愉快。