Shadowsocks 原理详解


这个东西用的人不少,知道原理的人却不多,很多时候很多事情都是以讹传讹瞎起哄。本文主要分析Shadowsocks实现的技术原理,讨论Shadowsocks的安全性。
Shadowsocks的架构
Shadowsocks(后文缩写为SS)由两部分组成,客户端和服务器端。常用的客户端有shadowsocks-win、ShadowsocksX-NG、shadowsocks-Qt5、shadowsocks-android…;常用的服务器端有Python版本,Go语言版本,C、C++……。客户端启动后会开启一个本地代理(一般用HTTP Proxy),通过修改操作系统配置或者浏览器配置把访问请求转发给本地代理。当我们通过浏览器访问某个地址的时候,数据会被转发到本地代理,由本地代理加密后转发到服务器端,服务器端处理完请求后把数据加密后返回给客户端的本地代理,本地代理再次返回给浏览器。



要澄清两点:1. SS协议和Http Proxy、Socks5没有半毛钱关系,这两个协议是浏览器或者操作系统所支持的标准代理协议,SS的架构中只是用这两种协议作为“获取用户请求”的手段而已。2. SS协议中没有任何控制流,本地代理获取用户原始TCP/UDP数据包获取之后会直接取出Data部分,重新构造一个IP数据包(可能是TCP或者UDP,和用户原始请求是TCP还是UDP有关系。),目标地址和端口是服务器地址,数据包的Data部分是加密后的用户原始Data。
Shadowsocks数据包分析
我们通过一个例子来分析问题更容易理解,我通过SS代理访问http://php.net/robots.txt。



前三条是TCP握手我们无视后面是162字节的请求数据包,接着是服务器端回复一个ACK确认(60)字节,接着是服务器返回651字节的回复数据包;紧接着服务器发送60字节的TCP控制数据包扩大数据窗口;客户端回复54字节的ACK确认数据包。后面4条是TCP的关闭动作。
我们关注的重点是162字节的请求和651字节的回复是什么内容:
SS请求数据包、



关注IP头部和TCP头部,这两部分信息是源地址是本地代理的IP地址和端口;目标地址是服务器端的IP地址和端口,Data部分108字节是通过AES加密的原始请求,我们把它解开看一下。



只看内容的话我们已经能够猜出个大概了,这是用户实际请求的数据包。SS的协议格式非常简陋,由两部分组成



* 目标地址有三部分组成,类型是一个字节的枚举类型
0x01:主机部分是 IPv4地址0x03: 主机部分是变长字符串,第一个字节表示长度后面是数据。最多承载255个字节的数据0x04: 主机部分是IPv6地址端口是两个字节的无符号整数类型。
* 数据部分就是用户原始的请求(TCP或UDP数据包部分)
截图中03表示主机是一个变长字符串(域名),07表示字符串的长度是7个字节,70 68 70 2e 6e 65 74是php.net,00 50是端口转换成十进制是80。再往后就是HTTP的协议部分了(TCP的Data部分)
SS回复数据包



这是SS服务器回复给本地代理的数据包。IP和TCP头部没有什么特殊的,直接看Data部分,一共597字节。也是加密后的数据,我们把它解出来。




服务器端没有增加特殊头部,直接把原始数据返回。

SS安全性
SS中本地代理和服务器通讯数据包都是经过加密的,DPI(深度数据包检测)只能检测到IP头部和TCP/UDP头部,无法对内容进行检测,而VPN之类的就特别容易被检测到了。想检测SS只能通过“流量特征”(数据包的结构)推测,但是使用SS一般选择带IV模式的AES加密算法作为加密方法(不了解AES的朋友请参考公众号的《深入浅出AES加密》),利用IV对数据做随机化,使每次请求的数据包都不一样,一般很难形成“流量特征”。如果SS无法使用那么一定是由于服务器端IP地址被限制了,被限制的原因也绝对不是由于SS被识别到了(除非谁有通天的能耐破解AES)。
SS改进
SS的设计很low(好吧,其实也没啥设计),效率也很差,特别是HTTP之类的短连接简直是灾难。一个Web页面中可能包含40-50个请求那么相当于SS中转40-50次,所以并发压力很大。但是它实现起来特别简单,而且行之有效,这也许就是它美妙的地方。

没有评论: