Pages

Saturday, 25 November 2017

网络连接的封锁与反封锁

最近一段时间,针对网络连接的战争愈演愈烈,双方都在尝试不同的策略。以至于对于新人来说,很难理解哪些已经发生过,哪些还在尝试中。于是我打算写篇文章来简单介绍一下整个故事的来龙去脉。

史前时代

最早的封锁大约是 DNS 投毒和 IP 黑名单。具体细节这里不表,简单来说就是 1) 对于特定域名比如 google.com,你的浏览器解析不到正确的 IP 地址; 2) 即使碰巧解析到了正确的 IP 地址,由于 Google 在亚洲地区的 IP 地址就那么几个,发往这几个 IP 地址的数据包被全部丢弃(或 TCP Reset),也就导致了用户死活访问不到 google.com。

攻防战 1.0

由于被封的 IP 依然是少数,而 Google 在全球的 IP 数量庞大,于是网友们很快想到了解决方案,就是使用 hosts 文件指定 IP 地址。虽然亚洲地区的 IP 被封了,但美国、欧洲甚至是南美洲依然有可以访问的地址,速度慢是慢了点,但总比上不去的好。于是 hosts 文件这个方案流行了那么一段时间。
后来封锁升级了,不是针对 IP 地址的了,而是针对每一个网络连接。受限于为数不多的几个出入境节点,网民的每一个出境网络连接实际上都被扫描过一遍。于是网络协议最初设计时,并未考虑封锁这回事,无论是 HTTP 还是 HTTPS,只需要扫描每个连接的前几十个字节,就可以得到其目标地址(域名)。HTTP 是通过其 Host 头,而 HTTPS 是通过 SNI
至此,针对域名,没有封不掉的,只有不想封的。
在直线连接几乎不可能的之后,那就只能绕路了,也就是代理。代理的主要三种模式是 Socks、HTTP 和 VPN。三种模式各有利弊:
  • Socks 可以代理 TCP 和 UDP 连接,但其数据包是明文的,依然逃不过上述检测;
  • HTTP 可以有 TLS 加持,但只能代理 TCP 连接,对 UDP 无效;
  • VPN 可以代理包含 TCP / UDP 在内的各种连接,但 VPN 会转发几乎所有的数据,在可以访问 Google 的同时,可能就不能访问优酷了(地区限制)。
然后 Shadowsocks 横空出世。
Shadowsocks 本质上是 Socks 的加密版本,可选择多种加密方式。一旦加了密,其传输的数据就无法被第三方检测了。并且 Shadowsocks 在转发数据之前,可以对其目的地进行判断,比如可以只转发去往 Google 的流量,而优酷的流量依然直连。在经常一段时间的优化之后,Shadowsocks 可以达到一个全局较快的连接速度,比上述的几个代理方式都要好。
由于 Shadowsocks 太过火爆,其作者被公安机关约谈,勒令不得继续参于相关项目的开发。

攻防战 2.0

中国那么多人,要把相关人员一一找出来喝茶,也不是一件容易的事。封锁这事,还得从网络连接着手。
对于一台国内的机器往一个国外的服务器发送数据的网络连接,有两种检测方式,被动式和主动式。
被动式是指检测方只观察连接中传输的内容,当内容符合某种模式(比如关键字)的时候,就把连接中断,或者服务器 IP 列入黑名单。上述的所有封锁方式均为被动式。
而主动式指的是,当观察到一个不可识别的连接时,检测方主动发起一个去往服务器的连接,通过一些编造的数据,探测出服务器是不是一台代理服务器。
Shadowsocks 协议曾被指出一个严重的安全性问题。只需要不到 16 次主动探测,就可以 100% 断定服务器是否在运行 Shadowsocks。具体来说,初版 Shadowsocks 协议依赖于连接头部的某一个字节来读取目标地址,这个字节的取值只有三种。当这个字节的取值不合法时,Shadowsocks 会快速中断连接,否则继续读取剩下的内容。于是这一特征可被用于探测一个服务器是否为 Shadowsocks 代理。
为了应对这一探测方式,Shadowsocks 对其加密方式升级了两次(OTA 和 AEAD)。目前看来这一漏洞,以及其它可能的主动探测方式,都被避免了。
同时期还有多个流行的翻墙工具,其原理和 Shadowsocks 大同小异,这里略过。

番外篇 1.0

既然代理工具有漏洞,那么检测工具也一会有漏洞。只要发现并利用这些漏洞,一样可以突破封锁。
曾经有一个项目“西厢计划”,就是利用了检测工具的漏洞,伪造了一些数据包,使它在检测方看上去上一个网络连接,但在目的服务器看来又是另一回事。检测方以为自己已经封锁了该连接,但实际上并没有。
和 Shadowsocks 的升级一样,检测方的算法也一样可以升级。升级之后,西厢计划便失效了。

攻防战 3.0

从信息学的角度来说,Shadowsocks 协议是一个近乎完美的协议。它的数据完全随机,无法 100% 确定这个网络连接是否为 Shadowsocks。但从另一方面来说,网络数据并不是均匀分布的,保守来说,HTTP 和 HTTPS 流量占据了 70% 以上。而如果一个服务器接收的流量 90% 是杂乱无章的,那么它就很可疑了。虽然检测方不能严格证明那就是 Shadowsocks,但秀才遇到兵啊……
既然随机数据可疑,那我们就把数据伪装成 HTTP 或者 HTTPS 好了。由于 HTTPS 是大势所趋,并且 HTTPS 传输的内容天生不可能被破解,把代理数据伪装成 HTTPS 也是一个比较合理的选择。
由于检测方无法判断一个 HTTPS 连接是正常的网站流量,还是代理。如果封锁所有的 HTTPS 流量,那无疑是一个杀敌五百,自损一千的昏招。当然急病乱投医也是有可能的……

第二战场 1.0

所有的代理工具都不是系统自带的,用户使用代理工具之前,需要先下载和安装。于是封锁下载途径也是一种封锁。Apple 就按要求移除了所有 VPN 应用。此战场防御方完败 😂
目前明面上的攻防到此为止,接下来说说一些想法和揣测

攻防战 4.0

虽然流量经过了加密,但加密的只是内容,不能排除还有其它的特征。比如 TLS (HTTPS 所用的加密协议)的握手环节,客户端和服务器互相发送的数据是有规律的。比如握手三次,每一次的数据量大致是固定的。如果有一个连接,也有三次握手,每一次的数据量和 TLS 相当,但是内容是混乱的,那么这个连接是不是 Shadowsocks 连接呢?当然 Shadowsocks 有一些额外的数据,这个另说。
目前翻墙圈在这一问题上有很大的争论。对于检测方是否足够强的技术做类似的检测,以及是否有足够的把握只封代理都存在疑惑。但毫无疑问,这将是下一个值得研究的领域。
另一个热点是分布式或者P2P。
这一领域已经被 Tor 证明为成功或者失败了(取决于你怎么看待 Tor)。我个人不喜欢 Tor 因为它速度太慢。虽然 P2P 这一术语最近很热,听上去也很有希望,但实际上它并不适用于翻墙。翻墙的过程需要【墙内的P】2【墙外的P】,并不是任意两个 P 都可以自由组合的。
目前对翻墙 P2P 的研究和应用都比较少,前景不明朗,观望中。
以上是对翻墙历史的简单总结,希望对新人有帮助.
from  https://cnsteem.com/cn/@v2ray/6knmmb
---------------

Shadowsocks各分支的安全性


这里要说的安全性并不是指密码学上的那种,而是在防探测,防流量识别并阻断上的安全性(也许算隐匿性?),所以主要针对的就是服务端。现在服务端的版本主要有以下这几个分支:shadowsocks-libev,shadowsocksR-python,shadowsocks-python,shadowsocks-go,libQtShadowsocks。而其它的分支用的人太少,所以我也没有去研究代码。

在说这个问题之前,首先要提及一点:TCP是流协议,你需要假设它可能在任何地方被拆分开,后面内容过一会儿才收到。服务端在设计的时候应该遵守以上这点来设计协议或设计其行为。

目前主要在使用的协议,一个是原始协议,另一个是OTA协议,现在分别说说这两协议在各分支上的实现。以下内容为截止到20160921时的各分支的实现情况,若将来各分支修正了,那么以修正后的情况为准,下文仅以此作为示例说明。



针对原始协议,截止到本文发表前,在IV的部分实现有问题的分支为shadowsocks-python,libQtShadowsocks。首先它们的实现总是假设第一个TCP包一定能收到完整的IV,事实上如果第一个TCP包被拆开,那么会导致shadowsocks-python解密错误(使用了错误的IV)而断开连接,而libQtShadowsocks则直接整个服务端程序crash退出(数组越界断言)。在IV之后的协议头部分实现有问题的,除了shadowsocks-go是实现正确以外,其它分支(包括SSR)全都实现错误了,也就是说如果协议头部分的包如果被拆开,除了shadowsocks-go还能正常连接外,其它的全部都会断开连接。估计是最早的时候服务端某个分支是这么写的,然后其它分支都用相同的逻辑来写,导致全错了。

对于原始协议的安全性,它无法防止CCA攻击,也就是说总是可以有办法通过足够次数的主动探测从而确认这是SS服务器。尽管如此,各分支实现的细节还是有点差别。首先,在OTA协议出现之前,我写了一篇文章来说明这种攻击的可行性,并在之后给出了具体的攻击代码,在这个时候起码还是需要穷举至少256次来确认的,不过对于shadowsocks-libev需要更多的次数以绕过它的IV buffer以便使其重复IV检测失效,不管怎么说检测的代价还是比较大的,很多人怀疑这个检测代价太大,某防火墙应该是不会这么做的。但是后来,在OTA协议出现之后,各分支都在跟进,因为它能防止CCA攻击,理论上的安全性的确提升了,但现实是,除了shadowsocksR-python分支的安全性没有下降,所有其它分支的安全性全部严重下降!我确实想不明白为什么大家都要这么实现,难道是因为shadowsocks-libev是这么写,所以大家都那样写么?现在各分支的实现,只要不是强制使用OTA协议(即同时支持原协议和OTA协议的情况下),要主动检测它是不是SS服务器,下降到基本上只需要16次连接来确认了,这导致这个主动探测攻击进入了非常实用的阶段,我觉得这太可怕了,于是之前写了一段仅针对shadowsocks-go的检测代码,演示了最多只要32次连接就成功检测这是不是shadowsocks-go,而且能连同IV长度一并检测出来(如果IV已知那只要16次连接来确认),而且理论上还能检测出它是不是仅支持OTA或两协议都支持。现在的各SS分支的实现确实安全性非常差,除非强制开启OTA,否则只要是兼容原协议,16次试探就能定位封锁,问你怕不怕。

针对OTA协议,实质就是在原始协议的头部,添加一个标志位,以及末尾添加SHA1-MAC,而其它从客户端发向服务端的数据包,均添加包的长度及SHA1-MAC。对于这个协议的实现,shadowsocks-libev及其它大部分分支均假定第一个数据包必须包含整个带了SHA1-MAC的头部,否则断开连接。这样做没有安全性上的问题,但违反了TCP协议的行为规则。这方面同样也只有shadowsocks-go遵守了TCP协议的行为规则,但是却留下了安全性上的问题,导致OTA并没有对其产生安全性上的提升,相反的导致了更容易被检测的问题,成为了目前各分支里安全性最弱的分支。

总结,如果你用的是还不支持OTA的服务端,那么你应该庆幸,还不至于太糟糕, 否则如果你用的是支持了OTA但不是SSR的服务端,那么你必须开启OTA,或等待服务端修正这个问题再用,否则你的服务器和等着被封没有区别,看你运气了。当然如果你如果用SSR的服务端,那么你应该使用auth_sha1_v4协议保证其安全性(或至少也要auth_sha1/auth_sha1_v2,具体细节差别不在本文展开了)。混淆就无所谓安全性了,按需要来就好,设置plain亦可。

感谢阅读,欢迎评价,有误请指出.

from https://breakwa11.blogspot.ch/2016/09/shadowsocks.html

No comments:

Post a Comment