REALITY、Cloudflare 与 fallback 流量滥用
解释 VLESS + REALITY 中 server、SNI、target 与最终代理目标的分层,以及为什么把 Cloudflare 这类共享 CDN 作为 REALITY target 时,鉴权失败的 fallback 可让 VPS 变成可扫描、可滥用的 Cloudflare TCP 中转并消耗服务器流量。
[!info] related notes
- 所属 MOC: 计算机网络 MOC
- 相关概念: REALITY、VLESS、SNI、TLS 握手(TLS 1.3 主线)
- 易混淆概念: Cloudflare 优选 IP、ECH
- 相关资源: Cloudflare、代理协议
REALITY、Cloudflare 与 fallback 流量滥用
覆盖范围
本文专门解释一个容易被误解的现象:
为什么 VLESS + REALITY 把
cloudflare.com或其他 Cloudflare 托管域名作为 SNI/target 后,即使 VPS、SSH、面板、UUID 和 REALITY 私钥都没有被攻破,也可能出现大量流量被第三方跑掉?
核心原因不是“SNI 本身泄漏了密码”,而是:
REALITY 的鉴权失败 fallback
+
Cloudflare 的共享 CDN/Anycast 边缘
+
公网扫描
=
VPS 可能变成无需 VLESS 鉴权的 Cloudflare TCP 中转
先把四个地址彻底分开
典型配置可以抽象为:
server = VPS_IP
serverName/SNI = cloudflare.com
REALITY target = cloudflare.com:443
VLESS destination = youtube.com:443
它们回答的是四个不同问题:
| 字段 | 含义 |
|---|---|
server | 客户端真正建立 TCP/QUIC 连接的服务器,通常是 VPS |
serverName / SNI | 外层 TLS/REALITY ClientHello 声明的主机名 |
REALITY target | REALITY 借用 TLS 外观,以及非法连接 fallback 时实际转发到的真实 TLS 目标 |
| VLESS destination | 合法代理会话内部真正要访问的网站,例如 YouTube |
所以“使用 Cloudflare 做 SNI”并不意味着正常代理最终只访问 Cloudflare。
正常代理路径
合法客户端持有正确的 REALITY 参数和 VLESS 身份信息:
Client
│
│ TCP → VPS_IP:443
│ SNI = cloudflare.com
▼
VPS / REALITY
│
│ REALITY 验证成功
▼
VLESS
│
│ destination = youtube.com:443
▼
YouTube
这里:
- Cloudflare 是外层伪装目标;
- YouTube 才是内层代理目标;
- SNI 不是 VLESS 最终 destination。
为什么非法连接没有被直接 DROP
REALITY 的目标之一是让服务端端口面对非 REALITY 客户端时仍表现得像正常 TLS 服务。
如果所有非法请求都立刻 reset:
random ClientHello
→ VPS
→ immediate reset
服务行为可能更容易与正常网站区分。
因此 Xray 的 REALITY 实现采用:
REALITY 验证失败
→ 直接转发到 target
官方文档明确说明:不是合法 REALITY 请求的流量会被直接转发至 target。
普通 target 为什么风险较小
假设:
target = ordinary.example:443
fallback 链路通常是:
陌生客户端
↓
VPS
↓
ordinary.example:443
第三方能获得的只是“通过 VPS 访问这个普通目标”的能力,通用价值较低。
Cloudflare target 为什么完全不同
Cloudflare 的 proxied hostnames 共享 Cloudflare 公布的 IP 地址范围,这些地址构成 Cloudflare Anycast 网络。
逻辑上可以理解为:
Cloudflare Edge IP
├── site-a.example
├── site-b.example
├── site-c.example
├── *.workers.dev / 其他租户服务
└── 大量其他 proxied hostnames
如果 REALITY target 解析到了 Cloudflare Edge:
VPS
↓
Cloudflare Edge IP:443
Xray fallback 转发的是陌生客户端的 TLS 字节流。第三方可以发送自己的 ClientHello,其中 SNI 指向另一个 Cloudflare 托管 hostname。
于是形成:
第三方客户端
│
│ 未通过 REALITY 鉴权
▼
VPS:443
│
│ REALITY fallback
▼
Cloudflare Edge:443
│
│ 根据第三方 ClientHello 中的 SNI 处理
▼
第三方希望访问的 Cloudflare 托管站点
对第三方而言,这台 VPS 就变成了一个:
通往 Cloudflare 网络的公开 TCP 端口转发器 / acceleration node。
Project X 官方文档对这一点有直接 WARNING:当 target 位于 Cloudflare CDN 等特殊共享网络时,服务器相当于 Cloudflare 的端口转发,可能在被扫描后被滥用并“偷跑流量”。
为什么不需要破解 UUID
这条滥用路径发生在:
REALITY 验证失败
→ fallback
而不是:
REALITY 验证成功
→ VLESS UUID 验证成功
→ 正常代理
所以滥用者不必知道:
- VLESS UUID;
- REALITY 私钥;
- shortId;
- 面板密码;
- SSH 密钥。
从安全事件判断上,这是一个关键区别:
流量被大量消耗
≠ 必然代表主机被入侵
≠ 必然代表 VLESS 凭据泄漏
服务端可能只是把一个“为了伪装而设计的 fallback”暴露成了有实际价值的公共中转。
为什么会被发现
公网服务会长期遭遇自动化扫描。
扫描者不需要一开始知道它是 REALITY,只需要测试:
VPS_IP:443
然后观察:
- 是否接受 TLS;
- 发送特定 SNI 后是否能到达 Cloudflare;
- 是否能稳定转发;
- 带宽和延迟是否优秀。
一旦一个 VPS 对 Cloudflare fallback 很稳定,它就可能被识别成可用的 Cloudflare 反代/中转 IP,随后被测速池、脚本或更多客户端重复使用。
为什么 1000 GB 可以很快被跑光
带宽换算说明这种现象在数量级上并不反常。
若按十进制约 1 TB 计算:
1 TB ≈ 8 × 10^12 bit
持续 24 小时跑完约需要:
≈ 93 Mbit/s 平均带宽
如果只用 8 小时:
≈ 278 Mbit/s 平均带宽
对于 1 Gbit/s 级 VPS 端口,这种吞吐完全可能出现。因此“一晚跑完约 1000 GB”从网络容量上并不要求服务器被完全接管。
实际账单还取决于云厂商按入站、出站还是双向统计。
“偷域名”为什么会被社区这样称呼
在 REALITY 中文语境中,“偷域名/偷 SNI/偷证书”通常不是指:
- 控制了别人的 DNS;
- 获取了域名注册权;
- 入侵了 Cloudflare。
它更接近:
选择一个并不属于该代理服务的真实第三方站点,借用它的 TLS 证书/握手外观作为 REALITY 的 target/serverName。
Project X 中文 REALITY 文档本身也使用“偷同 ASN 的证书”“偷了 Cloudflare 这种免费 CDN 的证书”的说法。
所以“偷域名容易被偷流量”是一句不够精确的社区简写。更完整的因果链应该是:
借用第三方域名做 REALITY target
↓
如果这个 target 位于共享 CDN
↓
非法连接 fallback 到共享 CDN Edge
↓
VPS 获得通用 CDN 中转价值
↓
被扫描发现
↓
第三方持续经过 VPS 传输
↓
VPS 流量额度被消耗
真正危险的是共享 CDN target + fallback,而不是“域名不是自己的”这一事实本身。
与 Cloudflare 优选 IP 的关系
Cloudflare 优选 IP讨论的是:
客户端主动挑选一个到自身网络质量更好的 Cloudflare 边缘入口。
REALITY fallback 滥用则是:
第三方把某台暴露公网、能转发到 Cloudflare 的 VPS 当作额外中转入口。
两者不是同一技术,但在社区里都可能被描述成“CF 反代 IP”“优选 IP”“中转 IP”,因此容易混淆。
可以用下面的方向区分:
正常 CF 优选:
Client → Cloudflare Edge → 自己的 Cloudflare Zone
REALITY fallback 滥用:
Third Party → 某人的 VPS → Cloudflare Edge → 第三方需要的 CF hostname
与传统 Domain Fronting 的区别
传统 Domain Fronting 常见模型是:
TLS SNI = front.example
HTTP Host = hidden.example
依赖 CDN 在 TLS 层和 HTTP 层接受不同 hostname。
REALITY fallback 滥用的关键不是这套 Host/SNI 分离技巧,而是:
Xray 将未认证 TCP/TLS 流量转发到共享 CDN target
因此两者不要合并成同一个概念。
如何判断流量异常属于哪一类
可以按证据分层:
| 现象 | 更支持的假设 |
|---|---|
| VLESS 合法会话日志暴增,来源陌生 | UUID/订阅泄漏或节点被分享 |
| REALITY fallback/非认证连接流量暴增 | fallback 被扫描/滥用 |
| SSH 登录出现陌生来源或配置被改 | 主机账号可能被入侵 |
| 面板出现陌生会话/新增用户 | 面板凭据或应用可能被攻破 |
| 443 大量流量但无对应 VLESS 会话 | 优先检查 fallback / 反代 / 开放中转 |
| 流量都指向 CDN 边缘 | 重点检查共享 CDN target 风险 |
不要从“流量很多”直接跳到“服务器被黑”。
预防思路
1. 避免共享 CDN target
Project X 当前文档建议 REALITY 最佳实践优先选择更合适、网络特征接近的目标,而不是迫不得已借用 Cloudflare 这种免费 CDN。
2. 对入口 SNI 做过滤
官方文档建议可以在前面放 Nginx 等入口,过滤不符合预期的 SNI,避免任意 SNI 都借 fallback 进入共享 CDN。
3. 对 fallback 限速
Xray 提供:
limitFallbackUploadlimitFallbackDownload
可以对未通过验证的回落连接进行 token bucket 限速。
但官方也提醒:fallback 限速本身可能形成可识别特征,因此需要权衡。
4. 监控流量而不是只保护面板
即使:
- SSH 只允许密钥;
- 面板不暴露公网;
- UUID 足够随机;
- 系统没有入侵;
也仍然应该监控:
- 每小时/每天出入站字节数;
- 443 连接数;
- VLESS 合法会话与总 TCP 流量的差额;
- fallback 流量;
- 对外连接目的 ASN/IP;
- 异常峰值告警。
最小心智模型
记住这一条即可:
SNI 不是密码
Cloudflare 也没有“破解” VLESS
真正的问题是:
REALITY 为伪装而允许未认证流量 fallback
+
Cloudflare 是共享 CDN
=
VPS 可能被当成无认证 CDN 中转
学习检查
- 为什么
server = VPS_IP、SNI = cloudflare.com、destination = youtube.com可以同时成立? - REALITY 为什么要把未认证连接转发到 target,而不是全部 DROP?
- 为什么普通单站点 target 与 Cloudflare target 的风险不同?
- 滥用者为什么不需要知道 VLESS UUID?
- “偷域名导致偷流量”这句话缺失了哪几个关键中间步骤?
- 1 TB 在 8 小时内跑完大约需要多大的持续带宽?
- 如何从日志证据区分 UUID 泄漏与 REALITY fallback 滥用?
- 为什么仅仅加固 SSH/面板仍不能消除这个风险?
参考
- Project X — REALITY(官方警告与 fallback 限速): https://xtls.github.io/en/config/transports/reality.html
- Project X — VLESS Protocol: https://xtls.github.io/en/development/protocols/vless.html
- RFC 6066 — Server Name Indication: https://www.rfc-editor.org/rfc/rfc6066.html
- RFC 9849 — Encrypted Client Hello: https://www.rfc-editor.org/rfc/rfc9849.html
- Cloudflare — Cloudflare IP addresses / shared Anycast ranges: https://developers.cloudflare.com/fundamentals/concepts/cloudflare-ip-addresses/
- Cloudflare — CDN Reference Architecture / Anycast: https://developers.cloudflare.com/reference-architecture/architectures/cdn/