Skip to content

Instantly share code, notes, and snippets.

@yvbbrjdr
Last active June 14, 2020 22:29
Show Gist options
  • Save yvbbrjdr/ea80fc5ef21f1a518346c92bda611993 to your computer and use it in GitHub Desktop.
Save yvbbrjdr/ea80fc5ef21f1a518346c92bda611993 to your computer and use it in GitHub Desktop.
为什么应该用 SSL 翻墙

为了让更多人看懂,这篇文章使用中文撰写。 原文地址:https://gist.github.com/yvbbrjdr/ea80fc5ef21f1a518346c92bda611993

为什么应该用 SSL 翻墙

由Glype想到的


2013年7月8日,clowwindy写道:

为什么不应该用 SSL 翻墙

SSL 设计目标:

1. 防内容篡改
2. 防冒充服务器身份
3. 加密通信内容

而翻墙的目标:

1. 不被检测出客户端在访问什么网站
2. 不被检测出服务器在提供翻墙服务

SSL 和这个目标还是有一些出入。其中最大的问题是,2. 防冒充服务器身份 这个功能多余了。他会导致墙嗅探出证书信息,继而墙会知道服务器身份。如果墙知道一个服务器身份是用来翻墙的,它要做的仅仅是封掉使用这个证书的所有 IP。

墙看见的 SSL 握手响应头部如下:

(以下省略一个明显带有特征的Twitter HTTPS头)

这一段内容对翻墙的目标总结得非常到位:不被检测出客户端在访问什么网站以及不被检测出服务器在提供翻墙服务。具体来说:

不被检测出客户端在访问什么网站

是指即使翻墙包被截获并分析,也无法探知其中的内容。实现这一点非常容易,用加密算法就能实现。总之要让墙无法通过低成本的方法破解出内容即可。

不被检测出服务器在提供翻墙服务

这个比较复杂。半年来shadowsocks以及shadowsocksR的更新都是在做这件事情。它包含两个方面:

  1. 即使翻墙包被截获并分析,也无法区分其与其他数据包的区别(换言之,无法识别是否是翻墙包)。注意:识别翻墙包不一定需要解密其中的内容。
  2. 对于一个翻墙服务器,无法利用协议漏洞,通过各种攻击方式(重放攻击、篡改攻击、中间人攻击等等)来探测其是否是翻墙服务器。

现有的各种翻墙包结构基本无法实现上面的第2点,因为如果要自定义一个翻墙协议,一定会暴露出某些特征。我认为解决的方法是:不使用自定义的协议,而将翻墙协议建立在已有的、流行的、安全的协议之上,于是我想出一种利用SSL进行翻墙的方法,只是对原来的HTTPS进行一些不大的修改。

在阐述协议之前,我先利用clowwindy对于两个目标的描述说明为什么SSL适合翻墙:

SSL 设计目标:

  1. 防内容篡改 -- 防止篡改攻击
  2. 防冒充服务器身份 -- 防止中间人攻击
  3. 加密通信内容 -- 不被检测出客户端在访问什么网站

且因为每一次SSL协商时对称加密密钥都会不同,也顺便防止了重放攻击;因为HTTPS是一个非常常用的协议,HTTPS请求经过GFW时不会被怀疑,也无法检测是否是翻墙包。

下面用自然语言阐述这个翻墙协议:

众所周知,HTTPS是HTTP套了一层SSL。而由于SSL的加密特点,HTTP请求和响应的明文是不会被中间人截获的。事实上,不管SSL的下层协议是什么,其内容明文都不会被第三方获知。因此,我们可以将shadowsocks协议外套一层SSL来实现翻墙,唯一的改变是,将shadowsocks请求头的末尾加上\r\n(即HTTP行结束符)。如果GFW用HTTPS探测服务器,那么服务器返回一个正常的网站(比如Wordpress,甚至可以是自己真正的博客,可以用Nginx或者Apache实现),如果GFW用shadowsocks over SSL协议探测服务器,那么在收到第一个\r\n的时候服务器立即检查数据合法性,发现既不是HTTP协议又不是正确的(密码无误的)shadowsocks协议,那么立即关连接,或者返回HTTP 400 Bad Request(与HTTP处理不合法包的方法一样)。这样在不知道密码的情况下,GFW只能探测出这是一个HTTPS服务器,而不知道其是否运行shadowsocks over SSL。

剩下的问题是HTTPS证书。那么随便弄一个自签名证书,或者申请一个免费的就行了,再让客户端信任一下。

@qzworld
Copy link

qzworld commented Nov 7, 2017

请问这个思路有下文了吗? 最近有同样的思路,Google了一下发现这篇文章。谢谢。

@sqd
Copy link

sqd commented Aug 17, 2018

@qzworld 我也有了类似思路,自己做了一个 https://github.com/sqd/zhexingsun 。但是它是先在本地劫持所有HTTP/HTTPS请求,然后作为HTTPS发送给代理服务器。这样流量特征就和HTTPS完全一样(因为确实是真实的HTTPS请求)。

(我搭了一个demo,欢迎私信要密码)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment