Stunnel历史悠久、精悍通用,是不可多得的跨境加密隧道建立及代理转发工具,支持的应用层协议众多,包括HTTP/1.1 CONNECT over TLS。官网介绍简明扼要:一个设计用于TLS加密的代理。
Stunnel is a proxy designed to add TLS encryption functionality to existing clients and servers without any changes in the programs' code. Its architecture is optimized for security, portability, and scalability (including load-balancing), making it suitable for large deployments.Stunnel是一个代理,旨在向现有客户端和服务器添加 TLS 加密功能,而无需对程序代码进行任何更改。其体系结构针对安全性、可移植性和可伸缩性(包括负载平衡)进行了优化,使其适用于大型部署。
不管新旧、好用最重要,更何况运营商(不仅国内)对UDP及其上的Wireguard、QUIC等很难有根本性的策略变化,那我们就用Stunnel这个精悍的工具来搭建基于TCP的跨境通道和机场。Stunnel用于加密隧道建立及转发代理,现有的“教程”多半是不对的、误人子弟的。
1.必备条件
首先以及最后,一台境外VPS,可访问受限站点和服务。
Stunnel可以部署在Linux(包括OpenWRT)、Windows、Android等系统上,所以除了具备公网IP的VPS作为服务端外,对客户端没有要求。由于其采用标准化协议,服务端部署上线后,移动端App(ShadowRocket、Clash等)可以直接添加Socks over TLS等标准化协议节点,无需插件、无需顾虑支持问题。同时,作为采用了OpenSSL的“标准化组件”,Stunnel可直接使用apt、apt-get和yum、opkg通过官方源安装即可,无需下载、编译,OpenWRT中luci 也可直接安装,本体大小不足80k。所以,仅仅用精悍来形容stunnel是过于保守了。
2.VPS上部署stunnel服务端
2.1 安装与环境检查
本文以debian/ubuntu为例。首先,使用apt安装stunnel4。
apt install stunnel4 -y #apt install stunnel -y #与上一命令等效
stunnel4为stunnel的“新版本”,stunnel在系统中仅仅保留为stunnel4的软链接,所有守护进程名称及服务标识均为stunnel4,如stunnel4.service。
安装完成后,需要检查一下/etc/sysctl.conf和/etc/default/stunnel4两个文件。其中,/etc/sysctl.conf为检查ipv4转发是否开启,取消注释并将设为1后,使用sysctl -p命令即时永久生效。
/etc/default/stunnel4则修改ENABLE=0为ENABLE=1,该文件仅Ubuntu 18.04以下需要检查,较新版本无需操作。
# Julien LEMOINE <speedblue@debian.org> # September 2003 FILES="/etc/stunnel/*.conf" OPTIONS="" # Change to one to enable ppp restart scripts PPP_RESTART=0 # Change to enable the setting of limits on the stunnel instances # For example, to set a large limit on file descriptors (to enable # more simultaneous client connections), set RLIMITS="-n 4096" # More than one resource limit may be modified at the same time, # e.g. RLIMITS="-n 4096 -d unlimited" RLIMITS=""
2.2 配置stunnel服务端
stunnel配置文件位于/etc/stunnel/目录下(/etc/default/stunnel4文件已有指明),一般采用stunnel.conf以便于记忆管理。配置文件中的选项和值的定义、说明请参阅老E的前文「stunnel配置文件主要选项」,不再重复。对应于不同的验证方式选择,分别分享两份样例配置文件。
采用证书验证配置方式,需要使用OpenSSL生成自签名证书和私钥,stunnel支持pem和p12(pkcs12)两种证书格式,一般我们采用PEM格式,ACSII编码方式便于拷贝粘贴、密钥交换。
openssl req -nodes -new -days 365 -newkey rsa:2048 -x509 -keyout /etc/stunnel/2048key.pem -out /etc/stunnel/2048cert.pem cd /etc/stunnel && openssl pkcs12 -export -in 2048cert.pem -inkey 2048key.pem -out 2048pks.p12 base64 2048pks.p12 > 2048pks.base64
生成自签名证书后,配置stunnel.conf文件如下:
syslog = no debug = 3 output = /var/log/stunnel4/stunnel.log pid = /var/run/stunnel4.pid [stproxy] ;client = no ;connect = [host:]port accept = 8443 cert = /etc/stunnel/2048cert.pem key = /etc/stunnel/2048key.pem ;requireCert = yes ;CAfile = /etc/stunnel/ccert.pem ;CApath = /etc/stunnel/certs protocol = socks
Stunnel配置文件中至少应包含一项服务/service,用封号(;)作行注释。这里的“[stproxy]”即指定了一项服务,“[stproxy]”以上的为全局配置选项,以下的为stproxy服务配置选项。client指定了该服务是否为客户端,默认为no,因此服务端可直接忽略或删除该行。accept、connect分别指定服务监听地址和端口、链接上级(代理服务端)的监听地址和端口,省略地址表示在所有接口的指定端口上监听,这里我们不使用connect行,由stunnel直接进行socks代理转发。下面两行,在不使用CApath选项的前提下,cert、key分别采用绝对路径指定了证书和私钥文件。
重要:拷贝2048cert.pem文件或其内容,以供客户端对服务端进行验证。TLS体制下,首先是对服务端的验证以避免身份仿冒,其次服务端对客户端的验证是可选的,默认情况下,stunnel关闭了客户端验证,需要通过显式定义requireCert=yes以开启。
最后一行的protocol指定了采用socks协议,我们的目标是搭建socks VPN,因其工作在应用层之下,标准化且适配广泛。以上配置完成后即可启动stunnel4服务。
systemctl start stunnel4.service #service stunnel4 start #systemctl status stunnel4.service
PSK预共享密钥验证方式
stunnel同样支持PSK预共享密钥验证方式,除身份验证外,PSK主要用于密钥生成前的数据加密、密钥生成及密钥交换,对应的配置文件中通过ciphers加以指定。
syslog = no debug = 3 output = /var/log/stunnel4/stunnel.log pid = /var/run/stunnel4.pid [stproxy] ;client = no ;connect = [host:]port accept = 8443 ciphers = PSK PSKsecrets = /etc/stunnel/pskexample.txt protocol = socks
和证书验证方式相比较,仅仅是更改了两行,ciphers=PSK指定了验证方式为PSK,PSKsecrets则以绝对路径方式指定了存储验证信息的psk文件。psk文件/etc/stunnel/pskexample.txt内容如下:
useridentity:aaabbb...111fff
psk文件内容为identity:presharedkey格式,预共享密钥不能少于32个16进制字符(0-f),最长不超过64个16进制字符。如果存在非16进制字符,stunnel会自动过滤排除。
2.3 误区
- 服务端模式下,connect选项不是必要的,stunnel具备socks代理转发功能,因此也无需”tun2socks“类的额外工具;
- 部分服务配置选项也可以作为全局配置选项,作用范围不同,但不能将connect等仅服务选项写到全局模块中(第一个方括号以上);
- 默认安全等级为2,因此不可使用2048位以下的RSA/DSA密钥;
- stunnel默认支持双栈,省略IP/HOST时使用”:::port“即开启双栈监听;
- verify虽然仍可使用,但官方早已申明弃用,应使用verifyPeer、verifyChain以及requireCert;
- 新手和小白不要随意修改样例文件中的全局配置,如pid等,除非你熟练掌握linux,老E不回答任何相关问题。
3.安装、配置stunnel windows客户端
官方网站下载「stunnel windows x64安装程序」,双击安装。stunnel会请求输入信息以生成证书,每一行都直接回车使用提供的默认值,第一行国家代码默认就是PL,表明了stunnel的“国籍”。安装完成并启动后,stunnel会驻守任务栏,点开任务栏图标,选择『Edit Configuration』即可打开配置文件。
Windows下,stunnel配置文件就位于其安装目录下的config目录下,除配置文件外,还有stunnel预置的和生成的证书文件,以及openssl主配置文件。所有可执行exe、动态链接库文件均位于安装目录下,没有系统盘存留。
配置文件中,除预留开启了gmail相关的服务外,其他均作为示例以分号注释。我们只需在文件末尾添加服务块内容即可。首先,需要将服务端证书拷贝至配置文件同目录下,这里使用了4096cert.pem的文件名称。然后,编辑添加以下服务块内容。
[socksproxy] client = yes accept = 10088 connect = server_ip_or_name:8443 ;cert = stunnel.pem ;key = stunnel.pem verifyPeer = yes CAfile = 2048cert.pem
其中,client=yes表明这是客户端(默认为no),accept为监听地址和端口,connect指定连接的远程服务端地址和端口。验证模块中,verifyPeer=yes表示需要对服务端(对端)进行验证,CAfile指定了相对路径的对端证书文件。
确保正确编辑、添加配置后,保存配置文件,在任务栏点开stunnel菜单,选择『Reload Configuration』,这是应该就已经连接成功了。还是使用curl -x 请求google网站进行测试,国家码应该是VPS所在地,本例中是ja。
如有问题,可通过stunnel任务栏菜单选择『Show Log Windows』查阅日志进行分析。
4.客户端直连
这里以iOS ShadowRocket为例,在配置好服务端后就可以直连上网。打开小火箭,点击右上角『+』加号添加节点,点击『类型』(默认为shadowsocks),在协议类型中选择『Socks5 over TLS』后自动返回到『添加节点』,填入stunnel服务端的ip地址、端口后,点击『保存』。这时,移动端就可以直连stunnel服务端了。
这,就是标准化。如果你的app不支持,卸了吧。
5.安全增强
我们可以分析得出在使用证书验证方式时存在很大的安全隐患,如果有人知道了服务端的ip和端口,就可以通过任何支持Socks over TLS的客户端连接服务端,况且总有无聊透顶的人不是?问题的根源在于我们没有配置对客户端的验证。因此,我们需要取消服务端配置文件中以下两行的注释,开启服务端对客户端的验证。
;requireCert = yes ;CAfile = /etc/stunnel/ccert.pem
同时,需要生成客户端证书和私钥,并上传/拷贝客户端证书至服务端服务端配置文件指定的目录下,并保证文件绝对路径、名称与配置文件指定一致。Shadowrocket支持base64编码的PKCS12格式证书以及证书密码,因此,对于移动端尤其是Shadowrocket有需求的,可在第一步服务端部署即直接采用p12证书,stunnel确定是支持的。
对于证书验证方式下的客户端身份验证,不再展开,仅补充三点:
- Windows下安装Stunnel过程中会创建证书文件stunnel.pem,可直接使用,取消客户端配置样例文件中的注释后重新加载配置即可;
- Stunnel配置文件中可采用CApath选项指定对端(们)证书目录,将所有对端证书存储于该目录下并以"证书Hash.0"命名,需注意采用的hash算法应与securityLevel要求匹配;
- Shadowrocket可在『https解密』处生成2048位CA证书/密钥,系统『通用』下对文件描述确认后安装导入,将该base64编码的p12证书导出后可提取公钥pem,当然也可不提取转为p12格式直接完整拷贝使用。
当然,换成PKS预共享密钥也是可以的,32-64个16进制字符在一定时期内足够强壮,如果混杂0-f之外的无效字符(stunnel会自动剔除),可以为家庭和soho用户提供足够的安全保障,但是,老E发现目前SR尚不支持Stunnel socks over TLS的PSK验证,坚持协议和app选择,就需要放弃移动端直连服务端的功能。
文章评论
麻烦请教一下,我的curl可以访问,但浏览器打不开对应网址是怎么回事呢?
@沐纪 该不会没有安装插件吧 插件协议选择socks5 指向客户端暴露的ip:port ,stunnel只是对外暴露了一个端口做socks5转发和加密,默认不是全局。如果安装了插件并做了相应的配置,那再看下防火墙,如果还不行的,麻烦tg @without_answer 再详细交流分析
请问一下,如果只用移动端连接,是不是不能服务器对客户端认证了?
@Vim 也可以 主要是建立私有CA 两边使用同一个CA颁发的证书就行 比较麻烦