Shadowsocks 对检测和封锁的探究
前言
在中国,Shadowsocks 是最流行的翻墙软件之一。
从 2019 年 5 月起,大量的中国网民反馈他们的 Shadowsocks 服务器被封锁了。
这篇报告是我们对中国的防火长城(GFW)是如何检测和封锁 Shadowsocks 及其衍生翻墙软件的初步调查结果。
通过网络测量实验,我们发现 GFW 会 ** 被动的监视网络流量 ** 从而识别出疑似 Shadowsocks 的网络流量;然后对对应的 Shadowsocks 服务器进行 ** 主动探测 ** 已验证其怀疑的正确与否。Shadowsocks 的封锁程度可能受 ** 人为因素 ** 在政治敏感时期的控制。
我们提出一种 ** 规避方法 **,即改变网络数据包在 Shadowsocks 握手阶段的大小。这种方法被证明可以在现阶段有效减少主动探测。我们会继续与开发者合作让 Shadowsocks 及其衍生工具变得更加难以封锁。
正文
[](# 主要发现 “主要发现”)主要发现
- 防火长城(GFW)已经启用主动探测的手段来识别 Shadowsocks 服务器。GFW 采用被动监测与主动探测相结合的方式:其首先监测网络连接找出疑似 Shadowsocks 的连接,然后再把自己伪装成一个客户端,尝试对疑似 Shadowsocks 的服务器进行连接,从而验证自己的猜测。我们知道 GFW 可以对多种翻墙工具进行主动探测,现在 Shadowsocks 也成了其中一员。
- 主动探测系统可以发送多种不同类型的探测。其中一些探测是基于对之前合法客户端建立的连接的 ** 重放 **;而另一些探测则似乎与之前的合法连接并不相关。
- 如同之前的研究发现,主动探测来自 ** 大量不同的源 IP 地址 **。这使得基于源 IP 来过滤 GFW 探测包不太可行。亦如之前的研究发现,网络层面的侧通道显示这些来自数以千计的 IP 地址的主动探测并非完全相互独立,而是源于 GFW 的集中控制。
- 很少量的(大于 13 个)合法连接即足以触发对于 Shadowsocks 服务器的主动探测。只要合法客户端还在使用服务器,主动探测就会持续下去。GFW 通常在合法连接到达服务器后的数秒内发送第一个主动探测。
- 一旦 GFW 主动识别出 Shadowsocks 服务器,GFW 可能会丢弃所有发送自服务器 IP 地址,或服务器 Shadowsocks 端口的数据包。但 GFW 也可能不立即采取封锁措施。Shadowsocks 的封锁程度可能受人为因素在政治敏感时期的控制。
- GFW 的被动监测模块至少会根据网络数据包的长度来怀疑可疑流量。改变数据包的长度,比如所在服务端安装brdgrd,即可通过干扰被动监测模块对 Shadowsocks 流量的识别,进而显著减少主动探测的数量。
[](# 我们怎么知道的? “我们怎么知道的?”)我们怎么知道的?
我们在境外搭建了自己的 Shadowsocks 服务器并从中国用客户端连接它们,与此同时,在服务器和客户端两端抓包进行分析。所有的实验都是在 2019 年 7 月 5 号到 2019 年 11 月 11 号之间进行的。其中的绝大部分实验都是在 2019 年 9 月 16 日开始的一次大规模封锁 后进行的。
在绝大部分实验中,我们使用了 shadowsocks-libev v3.3.1 作为客户端和服务端,因为它是一个被积极维护且具有代表性的 Shadowsocks 实现。我们相信我们所发现的这些弱点在其他 Shadowsocks 及其衍生工具,如Outline VPN,中同样存在。
若非明确指出,我们未对任何实验中的客户端及服务器的网络功能进行修改,比如更改防火墙的设置。Shadowsocks 可以使用不同的加密设置,我们对 Stream ciphers 和AEAD ciphers都进行了测试。
[](# 主动探测的一些细节 “主动探测的一些细节”)主动探测的一些细节
Shadowsocks 是一项加密通讯协议,其数据包的内容被设计得(应)不包含任何固定特征。其两种加密模式都基于一个主密码,两种模式分别为:Stream(不推荐使用) 和 AEAD (推荐)。这两种加密模式虽都要求客户端事先知道主密码;但是 Stream 加密模式的服务器仅能对客户端进行较弱的验证。除非使用额外的技术手段,两种模式都不能防御对之前发送过的验证数据包的重放攻击。
[](# 主动探测的类型及审查者意图 “主动探测的类型及审查者意图”)主动探测的类型及审查者意图
我们目前观察到五种不同的主动探测荷载。
基于重放的探测:
- 重放某一合法连接中第一个携带数据的数据包中的荷载。
- 重放某一合法连接中第一个携带数据的数据包中的荷载,但更改第 0 字节。
- 重放某一合法连接中第一个携带数据的数据包中的荷载,但更改第 0–7 和第 62–63 字节。
看似随机的探测(并非基于我们所观察到的合法连接):
- 荷载长度为 7 到 50 字节,占所有看似随机的主动探测的 70%。
- 荷载长度为 221 字节,占所有看似随机的主动探测的 30%。

我们怀疑 GFW 的主动探测系统根据服务器对这几种不同类型的主动探测的反馈来判定其是否为 Shadowsocks 服务器。
Shadowsocks-libev 有一个重放过滤器; 但是大多数的 Shadowsocks 实现则没有。重放过滤器可以防御一模一样的重放(类型 1),如果载荷的最初几字节被改变了(类型 2 和 3)那么过滤器就无法防御了。过滤器本身也不够阻止主动探测模块去比较服务器对多种探测的反应。
[](# 多少次合法连接就能触发主动探测 “多少次合法连接就能触发主动探测”)多少次合法连接就能触发主动探测
对主动探测的触发似乎需要达到一定的阀值。比如在一项实验中,仅仅 13 次连接就足以引起 GFW 的怀疑并触发主动探测。初步结果显示,使用了 AEAD 的 Shadowsocks,可能需要稍微多一点点的连接才会触发主动探测。
[](# 合法连接与主动探测的关系 “合法连接与主动探测的关系”)合法连接与主动探测的关系
我们让客服端每 5 分钟对 Shadowsocks 服务器进行 16 次连接。虽然我们的服务器触发了大量的主动探测,但不知为何,其并未被 GFW 封锁。

上图显示在客户端与服务器有通讯的时间里,服务器会收到主动探测。当合法客户端与服务器的通讯停止下来后,大部分的主动探测也停了。值得指出的是,每小时中主动探测的数量并非固定值,与合法客服端的连接数目比也并非 1:1。
[](# 主动探测的延迟性 “主动探测的延迟性”)主动探测的延迟性
GFW 的主动探测系统可以将合法连接的载荷保存下来,然后延迟一段时间再发起一个新的连接进行重放。下图显示了合法连接与重放攻击之间的延时关系。由于一个合法的载荷可能被多次重放(某一次实验中观察到的最大值为 47 次),我们呈现两组关系:桔黄色的线代表基于一个合法载荷的第一次重放;蓝色的线代表所有基于重放的探测(不限定为第一次)。
结果显示多于 90% 的重放攻击发生在合法连接发送后的一小时之内。观察到的最短的延迟仅有 0.4 秒,而最长延迟竟有大约 400 小时。

[](# 主动探测的源 “主动探测的源”)主动探测的源
我们在目前所有实验中总计观察到 3,5477 次主动探测。它们来自 1,0547 个不同的 IP 地址,IP 地址均属于中国。
** 源自治系统 **。主动探测来源占比最多的两个自治系统 AS 4837 (CHINA169-BACKBONE CNCGROUP China169 Backbone,CN) 和 AS 4134 (CHINANET-BACKBONE No.31,Jin-rong Street,CN),分别为中国联通和中国电信的主干网。这一结果与之前对 主动探测的研究 一致。

** 中心化结构。** 尽管这些主动探测来源于上千个不同的 IP 地址,有迹象显示它们的行为均受到一小撮进程的集中管控。下图显示了每个主动探测的 SYN 包所携带的 TCP timestamp 值。TCP timestamp 是一个 32 位的计数器,其以固定的速度进行增长。其不是一个绝对值,而是一个取决于 TCP 实现和系统上次重启时间的相对值。下图显示这些来源于上千个独立的 IP 地址的主动探测,共享着很少量的 TCP timestamp 序列。在这次实验中,至少观察到 9 个不同的物理系统或进程,而绝大多数主动探测似乎来源于同一进程。我们说 “至少” 和“似乎”是因为如果两个或以上的独立进程的截距非常相近,那么我们可能把它们误认为一个进程。序列的斜率显示 timestamp 的增长速度为 250HZ。

[](# 如何规避针对 Shadowsocks 的封锁? “如何规避针对 Shadowsocks 的封锁?”)如何规避针对 Shadowsocks 的封锁?
GFW 对于 Shadowsocks 的检测需要两步:
- 第一步,被动监测并识别疑似 Shadowsocks 的连接。
- 第二步,主动探测疑似 Shadowsocks 的服务器。
因此,为避免封锁,我们可以(1)设法避免被监测模块怀疑到,或者(2)让服务器以不被怀疑的方式回应主动探测。我们将展示如何通过安装改变数据包大小的软件来达到目标(1)。
Brdgrd是一款可以被安装在 Shadowsocks 服务器上,从而导致 Shadowsocks 客服端发送较小的数据包的软件。它设计之初衷是用来干扰 GFW 识别 Tor 节点,因为它迫使 GFW 在检测之前首先对 TCP 流进行复杂的重组。但这里我们利用它可以改变从客户端到服务器的数据包大小的功能。改变数据包的大小可以干扰流量识别环节,从而在极大程度上缓解主动探测。

上图显示了一个受到主动探测的 Shadowsocks 服务器,在开启 brdgrd 后的数小时内不再收到主动探测。而当我们关闭 brdgrd,主动探测立刻继续。我们第二次开启 brdgrd,主动探测在之后的 40 小时里完全停止,但之后又有些许主动探测。
另一组实验显示,在第一次运行 Shadowoscks 之初就启用 brdgrd 也许更加的有效。
Brdgrd 的原理是将 TCP Window Size 改写为一个小得罕见的值。因此,审查者可能可以检测出 brdgrd 被使用了。因此,尽管 brdgrd 可以在现阶段有效的减少主动探测,其不能被看作是一个一劳永逸的解决方案。
[](# 尚未解决的问题 “尚未解决的问题”)尚未解决的问题
尽管我们已经清楚 GFW 会主动探测 Shadowsocks 服务器,我们仍不清楚主动探测与 Shadowsocks 服务器被封之间的关系。我们有 33 组 Shadowsocks 服务器分布于世界各地。尽管它们中的大多数都遭受到了大量的主动探测,但是仅有 3 台服务器被封锁。更有趣的是,其中一台被封锁的服务器只被使用了很短的一段时间,因此受到的主动探测数量应该比很多未被封锁的服务器要少得多。
我们提出 3 种假设试图解释这一有趣的现象:
- Shadowsocks 服务器的封锁是由人为的因素控制的。也就是说,GFW 也许维护了一份在不同程度上被怀疑为 Shadowsocks 服务器的清单,然后根据人工因素来决定对服务器进行封锁还是解封。这一假设可以解释为什么更多的服务器是在政治敏感时期被封锁的。
- 另一个假设是 GFW 的主动探测对于一些我们实验采用的 Shadowsocks 实现无效。确实,我们被封锁的那 3 台服务器都是使用了与其他实验中的 Shadowsocks 不同的实现。如果 GFW 是根据某些 Shadowsocks 服务器实现对主动探测的特有反应来识别判断的话,那么这一假设更有可能为真。
- 第三个假设是对于 Shadowsocks 的封锁在地理上存在着不一致性。我们被封锁的那 3 台服务器所在的数据中心不同于其他大多数实验,使用的客服端也是位于一般的居民网络,而非数据中心。如果 GFW 更注意属于某些数据中心的 IP 地址,抑或更注意来自一般居民网络的客户端连接,那么这一假设更有可能为真。
[](# 致谢 “致谢”)致谢
我们想在此感谢以下人员对此主题的讨论和研究:
- Shadowsocks-libev 的开发者们
- OutlineVPN 的开发者们
- Eric Wustrow 以及其他多名来自科罗拉多大学博尔德分校的研究人员
[](# 联系我们 “联系我们”)联系我们
这篇报告首发于 GFW Report。我们还在 net4people 和ntc.party同步更新了这篇报告。
我们鼓励您公开或私下地分享与报告中的发现和假设相关的问题、评论或证据。我们私下的联系方式可见 GFW Report 的页脚。
参考来源:
[English Version: How China Detects and Blocks Shadowsocks]
日期: 2019 年 12 月 29 日,星期日
** 作者:** 匿名作者 A, 匿名作者 B, 匿名作者 C, 大卫 · 菲尔德 [David Fifield] , 阿米尔 [Amir Houmansadr]
to be continued…