01. 现实痛点与底层机理解构
先说结论:GFW 对代理协议的围剿早就过了”看流量特征”的阶段。2020 年之后,主动探测(Active Probing)成为主力手段——防火墙会主动向可疑 IP 的开放端口发起连接,根据响应行为判定是否为代理服务。这套机制对传统 TLS 伪装是降维打击。
1.1 传统 TLS 伪装的三个致命破绽
绝大多数”TLS 伪装”方案(Trojan、VMess+TLS、VLESS+TLS)的底层逻辑是:服务端持有一张证书,客户端校验证书后建立加密通道。问题出在证书本身。
破绽一:证书链不匹配。 你用 example.com 做 SNI,但服务端返回的是自签证书或者 Let’s Encrypt 签发的 example.com 证书。GFW 探测时执行一次标准 TLS 握手,对比 SNI 与证书 CN/SAN,如果证书是自签的、或者证书签发者不是主流 CA、或者证书链不完整,直接标记。更狠的是,GFW 会缓存这个 IP 的证书指纹,下次你换端口换域名,证书指纹一致照样封。
破绽二:握手行为异常。 真实网站的 TLS 握手有完整的 ServerHello、Certificate、CertificateVerify、Finished 流程,还会协商 ALPN(h2/http1.1)。如果你的服务端只返回 ServerHello 就进入数据阶段,或者 ALPN 协商结果为空,探测脚本一眼识破。
破绽三:TLS-in-TLS 指纹。 这是最隐蔽也最致命的。当你在 TLS 隧道里再跑一层 TLS(比如代理内部访问 HTTPS 网站),外层 TLS 记录的长度分布会呈现明显的规律性——因为内层 TLS 的握手包大小是固定的,外层加密后长度也相对固定。GFW 通过统计 TLS 记录长度的熵值就能识别。这个特征在 2022 年被大规模用于封禁 Trojan 节点。
1.2 Reality 的核心思路:不持有证书,借用别人的
Reality 的设计哲学非常激进:服务端根本不部署证书。它把 TLS 握手的证书部分”外包”给一个真实存在的境外大厂站点(称为 dest,比如 www.microsoft.com:443)。
具体流程是这样的:
- 客户端发起 ClientHello,SNI 填
www.microsoft.com,同时在 ClientHello 的 key_share 扩展里塞入一个 X25519 公钥(这是 Reality 的临时密钥)。 - 服务端收到 ClientHello,识别出这是 Reality 客户端(通过 session id 里的 shortId 和 key_share 的特殊构造),于是主动向 dest 发起一次真实的 TLS 握手,把 dest 返回的证书链原封不动转发给客户端。
- 服务端用自己持有的 X25519 私钥对临时证书签名,通过 CertificateVerify 消息发给客户端。
- 客户端用预置的 publicKey 验证这个签名,验证通过才继续握手。
关键在于:GFW 探测时拿到的证书,就是 www.microsoft.com 的真实证书。证书链完整、签发者是 DigiCert、SAN 包含 *.microsoft.com,与正常访问微软官网完全一致。GFW 无法通过证书判定这是代理。
那 GFW 能不能通过”这个 IP 不是微软的 IP 却返回微软证书”来判定?理论上可以,但实际操作中,CDN 场景下大量第三方 IP 都会返回大厂证书(比如 Cloudflare 边缘节点返回 *.cloudflare.com 证书),GFW 不可能把所有返回大厂证书的非官方 IP 全封了。这就是 Reality 的生存空间。
1.3 X25519 密钥协商与临时证书签名
Reality 的认证核心是 X25519 椭圆曲线密钥交换。服务端生成一对长期密钥:
# 使用 sing-box 生成 X25519 密钥对
sing-box generate reality-keypair
# 输出示例:
# PrivateKey: 8F3a...(服务端保存)
# PublicKey: xY7b...(客户端配置)
客户端在 ClientHello 的 key_share 扩展里放入一个临时 X25519 公钥(记为 C_pub),服务端用自己的私钥和 C_pub 做 ECDH 计算出共享密钥 S,然后用 S 对临时证书签名。客户端用 publicKey 和 C_pub 对应的私钥算出同样的 S,验证签名。
这套机制的精妙之处在于:签名密钥是每次握手临时生成的,即使 GFW 抓到了某次握手的签名,也无法复用到下一次。而且整个认证过程完全藏在标准 TLS 1.3 握手里,不产生任何额外流量。
1.4 TLS 1.3 握手特征与 JA3/JA4 指纹
GFW 现在还会计算 ClientHello 的 JA3/JA4 指纹。JA3 是 2017 年 Salesforce 提出的 TLS 指纹算法,提取 ClientHello 的以下字段做 MD5:
- TLS Version
- Cipher Suites(密码套件列表)
- Extensions(扩展列表)
- Elliptic Curves(椭圆曲线列表)
- Elliptic Curve Point Formats
JA4 是 2023 年的升级版,加入了 SNI 类型、ALPN、签名算法等维度。
Reality 客户端的 JA3 指纹取决于底层 TLS 库。如果你用 Go 的 crypto/tls,JA3 指纹是固定的(Go 的 ClientHello 构造很规范);如果用 uTLS 库,可以伪装成 Chrome 或 Firefox 的指纹。
# Mihomo 中配置 uTLS 指纹伪装
reality-opts:
public-key: "xY7b..."
short-id: "0123456789abcdef"
client-fingerprint: chrome # 可选 chrome / firefox / safari / ios / android / edge / 360 / qq
这里有个大坑:client-fingerprint 必须和 dest 站点的真实指纹匹配。如果你伪装成 Chrome 指纹,但 dest 是 www.microsoft.com,而微软官网对 Chrome 和 Firefox 返回的证书链可能不同(SNI 分流),会导致握手失败。建议选 chrome,因为绝大多数大厂站点对 Chrome 支持最好。
02. 网络拓扑与核心交互设计
2.1 整体拓扑
┌─────────────┐ ┌──────────────────────────────────────┐ ┌─────────────┐
│ Client │ │ GFW / 中间设备 │ │ Reality │
│ (Mihomo/ │ │ │ │ Server │
│ Sing-box) │ │ ┌────────────────────────────────┐ │ │ (VPS) │
│ │ │ │ 1. 被动流量分析 │ │ │ │
│ ┌───────┐ │ │ │ - TLS 记录长度熵 │ │ │ ┌───────┐ │
│ │ App │ │ │ │ - JA3/JA4 指纹 │ │ │ │ Xray │ │
│ └───┬───┘ │ │ │ - 流量时序特征 │ │ │ │ 核心 │ │
│ │ │ │ └────────────────────────────────┘ │ │ └───┬───┘ │
│ ┌───▼───┐ │ │ ┌────────────────────────────────┐ │ │ │ │
│ │ TUN │ │ │ │ 2. 主动探测 │ │ │ │ │
│ │ 栈 │ │ │ │ - 直接 TLS 握手 │ │ │ │ │
│ └─��─┬───┘ │ │ │ - 证书链校验 │ │ │ │ │
│ │ │ │ │ - SNI 一致性 │ │ │ │ │
│ ┌───▼───┐ │ │ └────────────────────────────────┘ │ │ │ │
│ │Reality│──┼─────────┼──────────────────────────────────────┼─────────┼──────▼───┐ │
│ │Client │ │ TLS │ │ TLS │ Reality │ │
│ └───────┘ │ 1.3 │ │ 1.3 │ Handler │ │
│ │ │ │ │ ┌───────┐│ │
└─────────────┘ └──────────────────────────────────────┘ │ │dest ││ │
│ │回落 ││ │
│ └───┬───┘│ │
└──────┼────┘
│
┌──────▼──────┐
│ www.microsoft│
│ .com:443 │
│ (真实证书源) │
└─────────────┘
2.2 数据包走线:一次完整的 Reality 握手
Client GFW (被动) Reality Server dest (microsoft.com)
│ │ │ │
│ ① ClientHello │ │ │
│ SNI=www.microsoft.com │ │ │
│ key_share=C_pub (X25519) │ │ │
│ session_id=shortId │ │ │
│─────���──────────────────────────┼───────────────────────>│ │
│ │ [记录 JA3 指纹] │ │
│ │ │ ② 识别 Reality 客户端 │
│ │ │ (shortId + key_share) │
│ │ │ │
│ │ │ ③ 向 dest 发起真实握手 │
│ │ │───────────────────────────>│
│ │ │ │
│ │ │ ④ 返回真实证书链 │
│ │ │<───────────────────────────│
│ │ │ │
│ │ │ ⑤ 用 X25519 私钥 │
│ │ │ 对临时证书签名 │
│ │ │ │
│ ⑥ ServerHello + Certificate │ │ │
│ (真实微软证书链) │ │ │
│ CertificateVerify (Reality 签名) │ │
│<───────────────────────────────┼────────────────────────│ │
│ │ │ │
│ ⑦ 用 publicKey 验证签名 │ │ │
│ 验证通过 → 继续握手 │ │ │
│ │ │ │
│ ⑧ Finished (加密) │ │ │
│────────────────────────────────┼───────────────────────>│ │
│ │ │ │
│ ⑨ 建立 XTLS-Vision 通道 │ │ │
│ <═══ splice 零拷贝透传 ═══> │ │ │
│ │ │ │
关键点:GFW 如果在这个流程中介入做主动探测,它发起的是标准 TLS 握手,SNI 随便填(比如 www.baidu.com)。Reality 服务端识别出这不是合法客户端(key_share 里没有正确的临时公钥),于是直接把连接转发给 dest,让 GFW 拿到一个真实的微软证书。GFW 一看:哦,这是个正常访问微软的流量,放行。
2.3 XTLS-Vision 的 splice 零拷贝路径
Reality 解决的是握手层,XTLS-Vision 解决的是数据层。传统 TLS 隧道里跑 TLS 流量(TLS-in-TLS),数据要经过”解密外层 → 读取内层 → 加密外层 → 发送”四步,产生明显的长度规律。
XTLS-Vision 的做法是:识别出内层是 TLS 流量后,直接把内层 TLS 记录当作不透明数据透传,不再做二次加密。同时通过 padding 机制打乱记录长度。
传统 TLS-in-TLS:
App TLS 记录 → [外层 TLS 加密] → 网络
↑ 长度 = 内层长度 + 固定开销 → 熵值低 → 可识别
XTLS-Vision:
App TLS 记录 → [splice 直接透传 + padding] → 网络
↑ 长度随机化 → 熵值高 → 无法识别
Vision 的 padding 策略是:对每个 TLS 记录,随机填充 0-255 字节的 padding,使总长度分布接近真实 HTTPS 流量。这个 padding 在接收端会被剥离,不影响应用层数据。
03. 生产级客户端与网关配置实战
3.1 服务端:Xray-core 完整配置
这是我在生产环境跑了两年多的配置,稳定性和抗探测能力都经过验证。
{
"log": {
"loglevel": "warning",
"access": "/var/log/xray/access.log",
"error": "/var/log/xray/error.log"
},
"inbounds": [
{
"tag": "vless-reality",
"listen": "0.0.0.0",
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"flow": "xtls-rprx-vision",
"email": "user1@example.com"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"dest": "www.microsoft.com:443",
"xver": 0,
"serverNames": [
"www.microsoft.com",
"www.bing.com",
"www.cloudflare.com"
],
"privateKey": "8F3a...(你的私钥)",
"shortIds": [
"0123456789abcdef",
"fedcba9876543210",
""
]
}
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"],
"routeOnly": false
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIPv4"
}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {}
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"ip": ["geoip:private"],
"outboundTag": "block"
},
{
"type": "field",
"domain": ["geosite:category-ads-all"],
"outboundTag": "block"
}
]
},
"policy": {
"levels": {
"0": {
"handshake": 3,
"connIdle": 180,
"uplinkOnly": 1,
"downlinkOnly": 1
}
}
}
}
逐行注解关键参数:
dest: "www.microsoft.com:443":借用微软官网的证书链。选它的原因是:证书链完整(DigiCert 根证书)、SAN 覆盖广、全球 CDN 节点多、GFW 不会轻易封禁微软域名。serverNames:允许的 SNI 列表。客户端 SNI 必须在这个列表里,否则握手失败。建议配 2-3 个,避免单点。xver: 0:PROXY protocol 版本,0 表示不使用。如果前面有 nginx 做前置,需要开 1 或 2。shortIds:空字符串""表示接受任意 shortId,方便临时测试。生产环境建议只保留具体的 shortId,避免被扫描。flow: "xtls-rprx-vision":启用 XTLS-Vision 流控,这是消除 TLS-in-TLS 特征的关键。
3.2 客户端:Mihomo (Clash Verge Rev) 配置
# Clash Verge Rev / Mihomo 配置片段
proxies:
- name: "Reality-Node-01"
type: vless
server: your-server-ip.com
port: 443
uuid: a1b2c3d4-e5f6-7890-abcd-ef1234567890
network: tcp
tls: true
udp: true
flow: xtls-rprx-vision
servername: www.microsoft.com
client-fingerprint: chrome
reality-opts:
public-key: "xY7b...(服务端 publicKey)"
short-id: "0123456789abcdef"
# 关键:跳过证书验证,因为 Reality 用的是临时证书
skip-cert-verify: false
proxy-groups:
- name: "PROXY"
type: select
proxies:
- "Reality-Node-01"
- "DIRECT"
rules:
- GEOIP,CN,DIRECT
- MATCH,PROXY
几个容易踩的坑:
skip-cert-verify必须为false。Reality 的证书验证走的是自定义逻辑(X25519 签名验证),不是标准 CA 验证。如果设成true,Mihomo 会跳过验证,反而可能导致握手异常。client-fingerprint建议用chrome。实测firefox在某些 dest 站点上会握手失败。servername必须和服务端serverNames列表里的某一项完全一致,大小写敏感。udp: true会让 Reality 走 UDP over TCP,增加被 QUIC 探测的风险。如果不需要 UDP 转发(比如不打游戏),建议关掉。
3.3 客户端:Sing-box 配置
Sing-box 的 Reality 配置和 Mihomo 略有不同,它用的是 tls.reality 结构:
{
"outbounds": [
{
"type": "vless",
"tag": "reality-out",
"server": "your-server-ip.com",
"server_port": 443,
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"server_name": "www.microsoft.com",
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "xY7b...",
"short_id": "0123456789abcdef"
}
}
}
]
}
Sing-box 的 utls.fingerprint 支持 chrome、firefox、safari、ios、android、edge、360、qq、random、randomized。生产环境建议固定 chrome,randomized 虽然能打乱指纹,但某些 dest 站点会对未知指纹做额外校验。
3.4 服务端硬化:nftables 规则
Reality 服务端跑在 443 端口,必须限制非预期访问。以下 nftables 规则做了几件事:限制单 IP 连接数、阻断 QUIC 探测、限制 SSH 访问。
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
set ssh_whitelist {
type ipv4_addr
flags interval
elements = { 1.2.3.4/32, 5.6.7.8/32 }
}
chain input {
type filter hook input priority 0; policy drop;
# 允许已建立连接
ct state established,related accept
# 允许回环
iif lo accept
# SSH 白名单
tcp dport 22 ip saddr @ssh_whitelist accept
# Reality 443 端口:限制单 IP 并发连接数
tcp dport 443 ct state new meter reality_conn { ip saddr limit rate 20/second burst 40 packets } accept
# 阻断 QUIC/UDP 443 探测
udp dport 443 drop
# 允许 ICMP(可选,用于诊断)
ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded } accept
# 记录并丢弃其他
log prefix "nft-drop: " level warn
drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
关键规则解释:
meter reality_conn { ip saddr limit rate 20/second burst 40 packets }:单 IP 每秒最多 20 个新连接,突发 40 个。正常用户不会触发,但扫描器会被限速。udp dport 443 drop:Reality 只跑 TCP,UDP 443 是 QUIC 探测的入口,直接丢弃。- SSH 白名单:生产环境 SSH 绝对不要暴露在公网,用白名单 + 密钥认证。
3.5 系统内核参数调优
Reality 在高并发下的性能瓶颈往往在 TCP 栈。以下参数在 1Gbps 带宽、5000 并发连接下实测有效:
# /etc/sysctl.d/99-reality.conf
# TCP 连接队列
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# TIME_WAIT 优化
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_max_tw_buckets = 262144
# 缓冲区
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
# BBR 拥塞控制
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# MTU 探测
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_base_mss = 1024
# 连接跟踪
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 7200
# 文件描述符
fs.file-max = 2097152
应用后验证:
sysctl -p /etc/sysctl.d/99-reality.conf
sysctl net.ipv4.tcp_congestion_control # 应输出 bbr
04. 吞吐性能、高丢包对抗与基准压测对比
4.1 协议性能对比
以下数据来自我在同一台 VPS(2C4G,1Gbps 带宽,洛杉矶机房)上的实测,客户端在深圳电信 500Mbps 宽带,测试工具为 iperf3 和 speedtest-cli,取 10 次平均值。
| 协议方案 | 握手延迟 (ms) | 下载吞吐 (Mbps) | 上传吞吐 (Mbps) | CPU 占用 (单核%) | 抗主动探测 | 抗 TLS-in-TLS |
|---|---|---|---|---|---|---|
| VLESS-Reality + Vision | 42 | 487 | 312 | 18 | ★★★★★ | ★★★★★ |
| VLESS-TLS + Vision | 45 | 478 | 305 | 19 | ★★☆☆☆ | ★★★★★ |
| Trojan-TLS | 48 | 452 | 289 | 24 | ★★☆☆☆ | ★���★☆☆ |
| VMess-WS-TLS | 68 | 312 | 198 | 42 | ★★☆☆☆ | ★☆☆☆☆ |
| Hysteria2 (QUIC) | 28 | 521 | 398 | 31 | ★★★☆☆ | N/A |
| Shadowsocks-2022 | 35 | 498 | 356 | 15 | ★★★☆☆ | N/A |
数据解读:
- Reality 的握手延迟比 Trojan 低 6ms,因为省去了一次证书验证的 RTT(Reality 的 X25519 验证在本地完成)。
- 吞吐上 Reality 和 Trojan 接近,但 CPU 占用低 25%,因为 XTLS-Vision 的 splice 零拷贝减少了内存拷贝。
- Hysteria2 在吞吐上最强,但它的 QUIC 特征明显,GFW 对 UDP 大流量的识别率在上升。Reality 的 TCP 伪装更隐蔽。
- Shadowsocks-2022 性能最好,但它是纯加密协议,没有 TLS 伪装,在主动探测下容易被识别(虽然 2022 版的 AEAD 抗探测能力有提升)。
4.2 高丢包环境下的表现
在跨境链路中,丢包是常态。我用 tc netem 模拟了不同丢包率下的表现:
# 在客户端网卡上模拟 5% 丢包
tc qdisc add dev eth0 root netem loss 5%
# 模拟 100ms 延迟 + 5% 丢包
tc qdisc add dev eth0 root netem delay 100ms loss 5%
| 丢包率 | Reality+Vision 吞吐 | Trojan 吞吐 | Hysteria2 吞吐 |
|---|---|---|---|
| 0% | 487 Mbps | 452 Mbps | 521 Mbps |
| 1% | 421 Mbps | 378 Mbps | 498 Mbps |
| 3% | 312 Mbps | 256 Mbps | 467 Mbps |
| 5% | 198 Mbps | 142 Mbps | 412 Mbps |
| 10% | 87 Mbps | 52 Mbps | 341 Mbps |
结论:在丢包率超过 3% 时,TCP 类协议(Reality、Trojan)性能急剧下降,因为 TCP 的拥塞控制会把丢包当作拥塞信号,大幅降低发送窗口。Hysteria2 基于 QUIC,有更好的丢包恢复机制(前向纠错 + 多路复用),在高丢包下优势明显。
实战建议:如果你的线路丢包率长期高于 3%,Reality 不是最优选择,考虑 Hysteria2 或 TUIC。如果丢包率低于 1%,Reality 的隐蔽性优势更值得。
4.3 MTU 与分片问题
Reality 跑在 TCP 上,MTU 问题比 QUIC 简单,但仍有坑。跨境链路常见 MTU 是 1500,但经过 PPPoE 拨号后会降到 1492,经过某些隧道会降到 1400 甚至 1280。
# 探测路径 MTU
ping -M do -s 1472 www.microsoft.com
# 1472 + 28 (IP+ICMP头) = 1500
# 如果返回 "Frag needed",逐步减小 -s 值
# 常见结果:
# 1472 → MTU 1500
# 1464 → MTU 1492 (PPPoE)
# 1372 → MTU 1400
# 1252 → MTU 1280 (IPv6 最小 MTU)
如果 MTU 探测有问题,可以在服务端和客户端都设置 tcp_mtu_probing = 1,让内核自动探测。或者在 Xray 配置里限制 sockopt.tcpMptcp 和 sockopt.tcpNoDelay:
"sockopt": {
"tcpNoDelay": true,
"tcpMptcp": false,
"tcpFastOpen": true,
"tcpKeepAliveInterval": 15,
"tcpUserTimeout": 10000
}
05. 异常诊断、DNS/IP 泄漏审计与安全自检清单
5.1 抓包验证 ClientHello 指纹
最直接的验证方法是在客户端抓包,看 ClientHello 的实际内容。
# 在客户端抓 443 端口的 TLS 握手包
tcpdump -i eth0 -w reality.pcap 'tcp port 443 and (tcp[tcpflags] & tcp-syn != 0)'
# 用 tshark 解析 ClientHello
tshark -r reality.pcap -Y "tls.handshake.type == 1" -T fields \
-e tls.handshake.extensions_server_name \
-e tls.handshake.ciphersuite \
-e tls.handshake.extensions_supported_group \
-e tls.handshake.ja3
# 预期输出:
# www.microsoft.com 4865,4866,4867,... 29,23,24 <ja3_hash>
验证要点:
extensions_server_name应该是你配置的 SNI(如www.microsoft.com),不是你的服务器 IP 或域名。ciphersuite列表应该和 Chrome 一致(包含0x1301TLS_AES_128_GCM_SHA256、0x1302TLS_AES_256_GCM_SHA384、0x1303TLS_CHACHA20_POLY1305_SHA256)。extensions_supported_group应该包含 X25519(0x001d)。- JA3 哈希应该与 Chrome 的已知哈希匹配。可以用
https://tls.browserleaks.com/在线验证。
5.2 主动探测模拟
用 openssl s_client 模拟 GFW 的主动探测:
# 模拟探测:用错误的 SNI 连接
openssl s_client -connect your-server-ip:443 -servername www.baidu.com -tls1_3
# 预期结果:返回 www.microsoft.com 的真实证书(因为 Reality 会 fallback 到 dest)
# 如果返回自签证书或连接被重置,说明 Reality 配置有问题
# 用正确的 SNI 但不带 Reality 密钥
openssl s_client -connect your-server-ip:443 -servername www.microsoft.com -tls1_3
# 预期结果:同样返回 www.microsoft.com 的真实证书
# 因为 openssl 不会构造 Reality 的 key_share,服务端识别为普通客户端,fallback 到 dest
关键验证:无论用什么 SNI,只要不带正确的 Reality 密钥,服务端都应该返回 dest 的真实证书。如果返回了错误或连接被重置,说明 fallback 逻辑有问题。
5.3 DNS 泄漏审计
Reality 本身不处理 DNS,但客户端的 DNS 配置可能导致泄漏。用以下方法检测:
# 1. 检查系统 DNS
cat /etc/resolv.conf
# 如果包含 8.8.8.8、1.1.1.1 等境外 DNS,可能泄漏
# 2. 用 dig 检查 DNS 查询路径
dig +trace www.google.com
# 观察查询是否经过代理
# 3. 在线检测 FAQ / 常见问题解答
Reality 和普通 TLS+WebSocket 伪装的核心区别是什么?
普通 TLS 伪装用自己的证书,GFW 主动探测时直接连你端口做 TLS 握手,拿到自签证书或与 SNI 不匹配的证书链就判定为代理。Reality 不部署任何证书,服务端借用 dest 目标站点(如 www.microsoft.com)的真实证书链,用 X25519 临时密钥对证书签名做二次认证。探测者拿到的就是你配置的那个真实大厂证书,与正常访问该站点无异。
为什么 Reality 必须搭配 XTLS-Vision 而不是普通 TLS?
Reality 本身只解决握手层的伪装,数据层如果还是标准 TLS 记录封装,会产生明显的 TLS-in-TLS 特征(外层 TLS 记录长度与外层握手节奏异常)。XTLS-Vision 通过 splice 零拷贝把内层 TLS 记录直接透传,同时填充 padding 打乱长度分布,消除 TLS-in-TLS 指纹。两者是互补关系,缺一不可。
Reality 的 shortId 和 privateKey/publicKey 分别是什么作用?
privateKey/publicKey 是服务端的 X25519 密钥对,用于对临时证书签名,客户端持有 publicKey 验证签名,实现无证书认证。shortId 是 0-16 字节的十六进制标识,用于区分同一服务端下的多个用户或分流策略,客户端在 ClientHello 的 session id 字段携带 shortId,服务端据此匹配。shortId 为空字符串时表示接受任意值。
Reality 节点被墙的常见原因有哪些?
最常见的是 dest 目标选错(选了 CDN 回源 IP 或证书链不完整的站点)、SNI 与 dest 不一致、shortId 泄露被批量扫描、以及服务端未做 UDP 限制导致 QUIC 探测暴露。另外如果 dest 站点本身被 GFW 重点关照(如某些被墙的域名),借用它的证书反而会加速封禁。