浅谈Steam社区屏蔽原理与解决方案,以及ASF安全部署
前言
2022年了,随着墙越来越高,以及部分运营商的墙中墙封锁,不仅Steam社区无法正常访问,就连商店也时不时抽风。
ASF的运行需要访问Steam社区检查游戏和掉卡情况,需要特殊手段才能访问到steam社区苟活。
好在Steam社区只是普通的封锁,并不是实质意义上的“墙”,通过一些手段仍然可以躲过互联网审查实现访问。
笔者根据自己的实际例子介绍阻断方式和解决方法,以及自己在部署时用到的ASF本地反代和https安全部署,希望有遇到同样问题的朋友可以有所帮助。
文章可能会有不严谨的错误,请大家积极指出,我也会尽量完善。
缩写术语
ASF(ArchiSteamFarm)
目前最主流的Steam挂卡程序,代码完全开源,不必担心留有后门,可以在多个平台上运行,现已有中文WIKI。本文主要记录在Ubuntu(Linux)服务器上的部署教程。但对于没有用过ASF并不熟悉Nginx的萌新来说,还是建议在Windows上调试成功后再转到云服务器上。
HTTP(Hyper Text Transfer Protocol)
超文本传输协议,日常浏览的各种网页都是通过HTTP协议传输,但是它的传输过程没有加密,不安全,所以被HTTPS替代。
目前市面上所说的支持HTTP一般是指HTTP和HTTPS功能都可以实现,而不是只支持HTTP。
TLS(Transport Layer Security)
安全传输层,它的前身是SSL,它实现了将报文加密后再交由TCP进行传输的功能。即HTTP + TLS = HTTPS
SNI(Server Name Indication)
服务器名称指示,简单来说,是用于在一台服务器的相同端口上部署不同证书的方法。服务器根据收到请求中的SNI域名来处理相应的请求,如果SNI域名为空,会按照预先设置好的默认域名处理请求。
CDN(Content Delivery Network)
内容分发网络,各个地区部署的服务器在一起形成的高速网络拓扑,用户在每个地区都能实现快速访问。CDN通过SNI响应不同的网站,同时也保护根服务器的安全。
Nginx
主流的高性能开源HTTP反向代理工具,主要用于反向代理、负载均衡和动静态资源分离。本文只用到了反向代理服务实现访问Steam社区和加防自己的ASF。
反向代理
在根服务器前部署一台外层服务器做为网关,用户只能访问到外层服务器,从而保护内网服务器不被暴露。做为网关,也可以对报文分析和修改。
代理服务器和根服务器部署在一台主机上称为本地反代。
1. ASF下载与安装
1.1 ASF版本选择
ASF有着Steam账号的高度控制权,所以安全部署尤为重要。
为保证程序不被恶意篡改,请务必在作者仓库上下载!
随着ASF版本的不断迭代,会修复许多安全漏洞,增强安全性,所以这里推荐使用最新稳定版。
我在部署时使用的版本是5.2.3.7,本文的所有操作均已在这个版本试验通过。
ASF在每个版本号下根据系统的不同又分为不同的文件,根据系统和CPU制造商来选择正确的版本,也可以直接下载源码编译。
我的服务器是跑在Intel CPU上的Ubuntu,所以下载ASF-linux-x64.zip
文件。
1.2 ASF下载
Linux上下载方式很多,例如用wget指令下载最新版的ASF-linux-x64.zip
。
wget https://github.com/JustArchiNET/ArchiSteamFarm/releases/latest/download/ASF-linux-x64.zip
由于不可描述的原因,Github在大陆下载缓慢甚至无法下载。解决方法网上也有很多,可以自己在电脑上下载后再上传到云服务器,也可以通过镜像站下载,这里不再过多赘述。
1.3 ASF安装及使用
Linux使用unzip
命令解压zip文件。
笔者在当前目录下新建了asf文件夹,并解压到里面。
mkdir asf
unzip ASF-linux-x64.zip ./asf/
解压后,运行ArchiSteamFarm
文件即可。
如果显示Permission denied
或文件名为灰色,则需要执行chmod +x ArchiSteamFarm
获取执行权限。
如果显示2022-03-16 15:29:39|ArchiSteamFarm-1377456|INFO|
相关字段,说明ASF已经成功安装。
2. Steam社区受屏蔽情况和理论解决方法(跳过也不影响)
起初,国内通过DNS污染以及HTTP报文关键字检测来拦截访问Steam社区内容。
在DNS污染下,浏览器访问会出现ERR_CONNECTION_TIMED_OUT
错误,因为DNS会被指向一个不可访问的地址,访问也就超时了。
解决方法就是在本地就做好解析,通过修改Hosts文件直连IP访问。
但是这不是重点,现在的Steam社区也不是这么简单的屏蔽方式。
2018年开始,Steam社区默认采用HTTPS链接,所有的浏览内容都会被加密,报文关键字检测的方法也就失效了。
随后出现了更深层次的审查方法,也就是要详细介绍的SNI检测。
2.1 SNI
正常情况下,TLS握手需要经历以下几个阶段。
在Client Hello阶段,由于双方还未协商好加密方式,报文仍然是明文状态,其中Extension字段包含了SNI信息,也就包含了当前正在访问的域名steamcommunity.com
,可以抓包获取到。
正常情况下,服务端根据这个域名发送相应的域名证书,进行接下来的握手步骤,在协商完后开始使用加密通信。
但是,SNI已经暴漏,审查机构会对当中的域名进行检测和阻断,也就是TCP重置攻击,通过对双方疯狂发送RST报文使连接重置,如果是浏览器访问就会出现ERR_CONNECTION_RESET
错误。
看完了可能会困惑,为什么要有SNI这个东西存在,握手过程没有它不也没有影响吗?
是的,在以前,每个服务器只会绑定一个域名,SNI完全没有存在的必要,访问某个服务器也一定只访问这个域名。
但是随着CDN的迅速发展,大多数网站为了提升响应速度和安全等级,都会将服务交给CDN托管,也就是说每个CDN服务器都会为多家网站提供服务,例如Steam就将业务部署在CDN服务商Akamai上。
CDN服务器会根据用户要访问的域名提供相应的内容,也就是识别SNI中的域名返回相应的页面。所以SNI对于现在的互联网环境已经不可或缺了。
2.2 那么有什么办法可以解决呢?
答案很碰巧,就是在Client Hello阶段不携带SNI或者携带无效的SNI,隐藏真实的连接网站来规避互联网审查。
当CDN检测到无效的SNI,会返回一张默认证书以便能够继续连接。碰巧的是,Akamai所返回的默认证书就是Steam的泛域名证书(毕竟Steam是最大的客户)。
这种技术叫做域前置,截至目前对Steam、Pixiv、Github等大型网站都有效。
下面就来介绍具体的实施过程。
3. 配置Nginx本地反向代理连接Steam社区(国外云服务器跳过)
好在这种阻断方式只是普通的封锁,并不是实质意义上的“墙”,可以通过本地反向代理绕过审查。
Windows端可以通过steamcommunity 302轻松解决(羽翼城大佬YYDS)。
Linux端可以参考他的文章 Linux/Macos环境下使用 steamcommunity 302 教程。
鉴于Nginx是主流以及它还跑有其他服务,这里根据大佬的思路在Nginx上实现。
将Steam社区等域名添加到Hosts文件中并指向localhost,这里的localhost仅做为一个本地安全跳板,供Nginx正常监听的同时又能防止流量外泄。Nginx将监听到的数据中的SNI信息去除,再送向CDN的IP,使用IP而不使用域名是为了防止DNS污染,既实现完整通信又不被互联网审查到。
3.1 配置Host
将访问困难的域名添加到Hosts文件中,配置如下:
127.0.0.1 steamcommunity.com
127.0.0.1 www.steamcommunity.com
127.0.0.1 store.steampowered.com
127.0.0.1 api.steampowered.com
一些云服务器在每次重启后会恢复默认Hosts,服务器提供商不同解决办法也不同,具体操作请自行百度。
下面的Nginx配置也会用到这些域名。
3.2 生成并安装证书
整个通信过程必须使用HTTPS加密协议,一是为了避免审查机构的报文关键字检测,二是Steam禁止明文HTTP访问,会自动跳转到HTTPS访问。
作为本地反代服务器,Nginx将监听的报文头处理后再发送给CDN,但是此时的Nginx服务器在宿主机看来是“不可信”的,除非强制让其可信,也就是在主机安装CA根证书,同时HTTPS反代也需要部署中间证书。
网上的许多教程都是用命令生成的证书,步骤比较复杂。不会操作的可以运行steamcommunity 302自动生成证书,上传到服务器。
302工具第一次使用后会在根目录生成一堆证书和密钥。
只需要将steamcommunity.crt
、steamcommunity.key
和steamcommunityCA.pem
三个文件上传到服务器。
三个文件的作用
steamcommunityCA.pem
:通过Openssl(302工具内置了Openssl)自签的CA根证书。只有在服务器中添加并信任根证书,它所签发的二级证书才会被信任。
steamcommunity.crt
和steamcommunity.key
:上述CA根证书签发的二级证书,Nginx在反代时使用该证书和私钥对流量进行加密。只有服务器信任了CA根证书,用二级证书加密的流量才会被视为安全。
将steamcommunity.crt
和steamcommunity.key
放在任意一个能读取到的路径就好。例如放在/etc/nginx/ca-certificates/
下方便管理,在Nginx配置文件中也方便填写相对路径。
不同的系统,安装CA证书的方法也不同。
例如在Ubuntu中,将steamcommunityCA.pem
命名为steamcommunityCA.crt
扔进/usr/local/share/ca-certificates/
,然后执行update-ca-certificates
安装。
3.3 配置Nginx参数
Nginx的配置文件位于/etc/nginx/nginx.conf
,这里给出基本配置:
server {# 部署一个虚拟主机
listen localhost:443 ssl;# 监听localhost的443端口
server_name steamcommunity.com;# 添加要监听的域名,与Hosts文件里的域名一致
server_name www.steamcommunity.com;
server_name store.steampowered.com;
server_name api.steampowered.com;
ssl_certificate ca-certificates/steamcommunity.crt;# 设置证书,这里使用了相对路径,绝对路径也行
ssl_certificate_key ca-certificates/steamcommunity.key;# 设置与证书匹配的密钥,同上
location / {# 当监听的端口检测到通往上述域名的流量时,执行下列操作
proxy_pass https://223.119.248.24/;# 将流量送往223.119.248.24主机,理论上任何一个Akamai服务器IP都可以
proxy_set_header Host $http_host;# 务必要加上,否则会报错URL非法
}
}
做完后记得让Nginx重新读取配置,也就是找到Nginx的主程序然后sudo nginx -s reload
。
问:为什么要监听443端口?
答:因为ASF使用Https协议请求Steam获取数据,也就是日常浏览网页的方式。Https协议默认通过443端口传输,所以proxy_pass https://223.119.248.24/;
可以不加443。
问:如果不配置证书或证书不可信会怎样?
答:如果在是浏览器访问,会提示连接不安全,但仍可以访问。如果是ASF或Steam客户端会默认禁止SSL证书无效的连接。
4. ASF配置
所有配置文件都存放在ASF根目录下的config
文件夹。
如果目录为空(初次安装),ASF会走默认配置;如果有配置文件,ASF会优先走文件里的配置,文件里没有写到的就走默认配置。
大多数配置文件都可以直接文本编辑或者通过ASF-ui修改,还可以用官方编写的ASF配置文件生成器修改后上传。
在官方Wiki上能找到所有的中文教程,这里只说下基本配置。
4.1 ASF.json配置
ASF.json
存放ASF的全局配置,主要是程序上的配置,基本格式如下:
{
"Headless": true,
"IPCPassword": "网页登入密码",
"SteamOwnerID": Steam帐号64位ID
}
变量名 | 数据类型 | 默认值 | 备注 |
---|---|---|---|
IPC | bool | true | IPC是否随进程一同启动。自V5.1.0.0版本开始,IPC已默认启用 |
IPCPassword | string | null | 访问IPC需要的密码,空即为不设置 |
UpdateChannel | byte | 1 | 更新及更新渠道设置,0为不更新,1为稳定通道,2为实验通道 如果Github渠道下载过慢。改变值以禁止自动更新 |
请务必设置IPC密码(IPCPassword),因为它是ASF的最后一道防线!
4.2 IPC.config配置
IPC
包括了各种ASF-api
和ASF-ui
界面,前者用于插件和界面的二次开发;后者是ASF自带的操作界面,默认部署在localhost:1242
端口上,通过浏览器就能访问。
IPC.config
存放HTTP服务端的相关配置(就是ASF操作界面的IP、端口、证书相关配置),配置如下:
{
"Kestrel": {
"Endpoints": {
"example-http4": {
"Url": "http://127.0.0.1:1242"
},
"example-http6": {
"Url": "http://[::1]:1242"
},
"example-https4": {
"Url": "https://127.0.0.1:1242",
"Certificate": {
"Path": "/path/to/certificate.pfx",
"Password": "passwordToPfxFileAbove"
}
},
"example-https6": {
"Url": "https://[::1]:1242",
"Certificate": {
"Path": "/path/to/certificate.pfx",
"Password": "passwordToPfxFileAbove"
}
}
}
}
}
变量 | 备注 |
---|---|
example-http4 | ASF使用IPv4和HTTP协议配置 |
example-http6 | ASF使用IPv6和HTTP协议配置 |
example-https4 | ASF使用IPv4和HTTPS协议配置 |
example-https6 | ASF使用IPv6和HTTPS协议配置 |
Url | 自定义链接名,使用域名和IP均可 |
Certificate | 使用HTTPS方式配置所需的证书及秘钥, 证书为pfx后缀,秘钥为字符串 |
IPv6尚未普及,一般使用IPv4部署ASF。
5. ASF 安全部署方案
平常在电脑上安装ASF,ASF-ui默认监听localhost:1242端口,考虑到仅在本地访问所以Http通信足矣。但如果是部署在服务器上,ASF-ui就要暴露在公网上被我们所访问。在公网上不能保证自己的IP不被监听,如果继续使用Http通信,流量中的明文密码将会泄漏。
因此,我们要将明文流量通过TLS加密,也就是使用Https协议,这样即使被别有用心的人监听到也只是加密的数据,对方无法解密,也就确保了密码相对安全。
ASF自身支持以Https方式启动ui,也可以使用Nginx本地反代Http协议下的ASF。
不管哪种方式,都需要申请ssl证书才能启用HTTPS。而申请ssl证书需要一个合法域名。国内几乎申请不到免费的域名,免费方案下只能从外网免费申请了,我用的是Freenom申请了一年的.ml后缀域名。
得到域名拥有权后再到国内云服务商上申请国内解析权,这样解析速度就和国内购买的域名一样了。
至于ssl证书申请,可以使用各大云免费申请一年,提交申请后半小时内就能下来。
如果域名备案了,就可以放心使用443端口,否则就会被互联网审查机构拦截阻断。毕竟ASF一般都是私用,选择默认1242端口就好。使用其他自定义端口没有实际增加安全性,但可以避免过于明显的扫描。
一定要记得在服务器上放行相应端口!
下面简述几种常见的安全部署方案:
5.1 本机运行 ASF(仅Http)
如果只部署在localhost,除非本机被攻破,否则ASF是安全的。
IPC.config配置如下:
{
"Kestrel": {
"Endpoints": {
"example-http4": {
"Url": "http://localhost:自定义端口"
}
}
}
}
5.2 公网运行 ASF(仅Https)
这种情况下,ASF将暴露到整个网络,必须配置SSL证书+Https协议,否则在数据传输过程中IPC密码将以明文显示,有被监听走的风险。
在申请的证书中下载pfx格式证书,然后在IPC.config中添加pfx证书和相应的私钥字符串。
IPC.config配置如下:
{
"Kestrel": {
"Endpoints": {
"example-https4": {
"Url": "https://自定义域名或IP:端口",
"Certificate": {
"Path": "config/我的域名证书.pfx",
"Password": "pfx证书附带的私钥"
}
}
}
}
}
如果使用相对路径,以ASF主程序的同级目录为当前路径。
5.3 公网运行 ASF(Http + Nginx Https反代)
此时的IPC.config配置可以默认,默认了话就是监听本地1242端口,然后通过Nginx监听公网443端口。
nginx.conf配置如下:
server {
listen 443 ssl;# 监听443端口,这里就包括了公网访问进来的端口
server_name www.我的域名.com;#添加要监听的域名,也就是申请的域名
ssl_certificate /etc/nginx/ca-certificates/我的域名SSL证书.crt;# 添加crt证书路径,绝对路径也可
ssl_certificate_key ca-certificates/我的域名SSL证书.key;# 同上
location / {# 当监听到上述域名的流量时,执行下列操作
proxy_pass https://localhost:1242/;# 将流量送往ASF监听的端口,默认是localhost:1242
# 使用下列的配置,ASF能正确检测到发送请求用户的IP地址
# 使ASF能够封禁真正的攻击者而非Nginx反代服务器
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
若访问页面出现502 Bad Gateway
,说明Nginx反代正常,但未监听到ASF流量,请检查IPC是否开启以及location匹配是否正确。
6. 结束语
这篇文章也是我查了很多资料后才写出来的,为了讲清楚从SNI检测到屏蔽手段也是把各种协议都复习了一遍,甚至还通过抓包来证明自己的理解,如果有错误希望大佬们指出。
最后,希望这篇文章能帮助到需要的人。
参考文章
- Linux/Macos环境下使用 steamcommunity 302 教程
- ArchiSteamFarm wiki
- 云服务器ASF挂卡——steamcommunity社区本地反代
- 在手机上访问discord和pixiv的正确姿势
- 浅谈asf ipc于服务器部署之安全方案
- 针对库存被盗帖,讨论 ASF 部署的安全性
- ASF IPC网页管理界面Nginx反代教程(带Https)
- 从 pixiv 免代理直连看 SNI 阻断及其绕过方法——域前置
- 自签CA对Steam社区进行反代
- HTTPS 之 SSL/TLS 握手协议(Handshake Protocol)全过程解析
- How does a TCP Reset Attack work?