随着人工智能发展,审查手段加入机器学习,使得原来Trojan方式因为含有TLS in TLS特征而有概率被筛选出来。现如今最隐蔽的手段莫过于利用Xray工具搭建vless通信协议+reality传输协议+xtls-rprx-vision流量控制的组合,如此一来审查者看到的是一次正常的 HTTPS 连接(单层 TLS),而非嵌套的 TLS in TLS

写在前面

原理解释

传统的Trojan方式,用户的代理客户端与代理服务器建立一个真实的TLS连接,通过这个加密的隧道,应用程序(比如浏览器)再与目标服务器(比如Google)建立一个TLS连接。这时浏览器与Google服务器就是端对端加密,任何人(包括代理服务)不能解密或者伪装发送信息。
浏览器 —- 代理客户端 ==== 代理服务器 —- Google
审查者只能看到我们通过443端口建立了TLS连接,看不到具体内容,以为我们在正常访问网页。虽然也做了认证不通过就将请求回落(Fallback)到自建网站这样防止主动探测的迷惑措施,但是随着机器学习的介入,这样的手段依旧可以被识破:
代理客户端与代理服务器之间的加密套娃无可避免的一点就是在每个包都会增加一个数据包头,加密层数越多,包头就会越重。最重要的,由于每个包都增加了相同长度,它可能具有某些统计学特征。

目前新的方案中,我个人理解如下:

  • Vless通信协议相当于是一个协议容器,它本身不对流量加密,对流量的处理也基本依靠传输协议和流量控制。
  • Reality传输协议,从根本上解决了TLS in TLS的现象。在握手阶段模仿一个国外网站的CDN节点(比如Google)与客户端建立TLS连接(当然这个TLS连接证书肯定是无效的,不过两边都会忽略这个问题)。握手成功后,当传输内容是TLS加密后的内容时,就不对流量进行二次加密了。
  • Vision流量控制则会填充数据包长度,来消除统计学特征。

前期准备

  • 一台外网服务器
  • 一个申请好的域名(假设为yangbo.party,自己处理好DNS解析)

本篇博文主要是介绍自己在服务器有网站,并且想把Xray隐藏在自己的网站后面。对自己而言,可以用浏览器正常访问自己的网站,可以通过Xray出墙;对审查者而言,只能看到我们的网站,以为我们的流量都是访问网站的。
如果你没有自己的网站,那就只需要把自己的Xray服务器伪装成一个国外网站的CDN,你也不需要建站、申请证书了,本篇教程不适合你,请转官方配置文档VLESS-TCP-XTLS-Vision-REALITY

安装Nginx和Xray

Nginx安装参见我之前的文章编译安装Nginx
Xray采用脚本一键安装

1
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

申请SSL证书

一键安装acme.sh

1
sudo apt update && sudo apt install -y curl socat && curl https://get.acme.sh | sh -s email=你的邮箱地址

官方分为两大类申请证书的方式:HTTP验证DNS验证,要是细分还有很多情况,这里我选择DNS验证,支持几乎所有的域名提供商。我的域名提供商是Namesilo,只要去Namesilo网站获取API,然后写入系统变量就好了。

1
echo "export Namesilo_Key='<key>'" > ~/.bashrc && source bashrc

然后尝试获取证书,成功之后记下证书路径就好了,其他的不用管了,每个月acme.sh会自动帮我续期证书。

1
acme.sh --issue --dns dns_namesilo -d yangbo.party -d www.yangbo.party --dnssleep 900 --server letsencrypt --force --reloadcmd "chmod -R 777 /root/.acme.sh/yangbo.party_ecc/ && systemctl reload nginx"

配置Nginx和Xray

先说原理:Xray监听443端口,通过层层验证判断是否为代理请求,如果不是就回落到Nginx监听的8080,如果是就建立通道。(其实整体跟Trojan一样,只不过验证阶段使用TLS,建立完请求后,不再对正常访问https网站产生的TLS流量加密)。
Nginx默认配置文件路径:/etc/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
user  root;
worker_processes 1;
pid /var/run/nginx.pid;
error_log /var/log/nginx_error.log;

events {
use epoll;
worker_connections 1024;
multi_accept on;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset utf-8,gbk;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 60;
client_header_buffer_size 4k;
open_file_cache max=102400 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 1;
client_header_timeout 15;
client_body_timeout 15;
reset_timedout_connection on;
send_timeout 15;
http2_recv_buffer_size 32k;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 3;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
server_tokens off;
access_log /var/log/nginx_access.log;
server { #如果有人访问http端口,就把它重定向到443端口,这就跟其他网站行为一致
listen 80;
server_name www.yangbo.party yangbo.party;
return 301 https://$server_name$request_uri;
}

server { #8080端口当作正常https网页去设置,注意替换证书路径
listen 127.0.0.1:8080 ssl fastopen=3;
http2 on;
server_name www.yangbo.party yangbo.party;
ssl_early_data on;
ssl_buffer_size 4k;
keepalive_timeout 75s;
ssl_certificate /root/.acme.sh/yangbo.party_ecc/yangbo.party.cer;
ssl_certificate_key /root/.acme.sh/yangbo.party_ecc/yangbo.party.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
client_max_body_size 20M;
client_body_timeout 12;
underscores_in_headers on;
location / {
root /www/;
expires 10h;
fancyindex on;
fancyindex_exact_size off;
fancyindex_localtime on;
fancyindex_header "/fancyindex/header.html";
fancyindex_footer "/fancyindex/footer.html";
fancyindex_ignore "fancyindex";
}
location ~* ^.+\.(jpg|gif|png|img|apk|tar.gz|wmv|jpeg|mp3|mp4|zip|rar)$ {
valid_referers none blocked www.yangbo.party yangbo.party;
if ($invalid_referer){
return 403;
break;
}
}
}
}

Xray默认配置文件路径:/usr/local/etc/xray/config.json,Xray配置较为复杂,可以参考官方wiki

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
{
"log": {
"loglevel": "debug",
"access": "/var/log/xray/access.log",
"error": "/var/log/xray/error.log"
},
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "使用xray uuid命令随机生成",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none",
"fallbacks": [
{
"dest": "127.0.0.1:8080",
"xver": 0
}
]
},
"streamSettings": {
"network": "raw",
"security": "reality",
"realitySettings": {
"show": false,
"target": "127.0.0.1:8080",
"xver": 0,
"serverNames": ["yangbo.party","www.yangbo.party"],
"privateKey": "运行命令xray x25519生成,其中的privateKey",
"password": "上一条命令xray x25519生成,其中的publicKey",
"fingerprint": "chrome",
"shortIds": ["运行 openssl rand -hex 4 命令生成"]
},
"sockopt": {
"tcpNoDelay": true,
"tcpFastOpen": true,
"tcpKeepAliveInterval": 30,
"tcpcongestion": "bbr"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"settings": {
"sockopt": {
"tcpNoDelay": true,
"tcpFastOpen": true,
"tcpKeepAliveInterval": 30,
"tcpcongestion": "bbr"
}
}
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
],
"routing": {
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "blocked"
}
]
}
}

systemctl restart nginx && systemctl restart xray

排错指南

理论上这一步结束,就应该完成了。试试看直接浏览器访问网页能不能正常回落。若不能,可以直接测试nginx监听的8080端口是否可以访问:curl -vk https://127.0.0.1:8080或检查端口是否被监听:ss -tuln或查看xray和nginx的日志(日志目录见配置文件)

一些网络优化

1
2
3
4
echo "net.ipv4.tcp_fastopen=3" >> /etc/sysctl.conf
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf
sysctl -p