处世如大梦,悟者能有几

— 宋·李纲

作者:pluto 更新时间:2026-04-17


摘要

VMess(V2Ray Message)是由 Project V 原创设计的加密代理协议,旨在对抗深度包检测(DPI)。本文从协议设计目标、数据结构、加密机制、认证流程、安全性分析及与同类协议的横向比较等维度,对 VMess 协议进行系统性研究。


1. 背景与设计目标

VMess 协议诞生于 V2Ray 项目(Project V),最初发布于 2015 年前后,其核心设计目标是:

  • 对抗基于特征的流量识别(如 GFW 的深度包检测)
  • 提供端到端的加密通信
  • 支持多种传输层协议(TCP、WebSocket、HTTP/2、gRPC 等)
  • 无状态设计,客户端与服务端无需握手即可直接传输数据

VMess 是一个基于 TCP 的应用层协议,所有数据均通过 TCP 传输。协议采用非对称格式,即客户端请求与服务端响应使用不同的数据结构。


2. 基础概念

2.1 用户身份标识(User ID)

VMess 使用 UUID(Universally Unique Identifier)作为用户身份标识,UUID 是一个 16 字节的随机数,格式如下:

de305d54-75b4-431b-adb2-eb6b9e546014

UUID 的功能等同于预共享令牌(Pre-shared Token),客户端与服务端通过 UUID 派生出用于认证和加密的密钥材料。

2.2 CmdKey

CmdKey 是从用户 UUID 派生的 16 字节密钥,用于 AEAD 认证模式下的头部加密:

CmdKey = MD5(UUID.Bytes() + []byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))

2.3 密钥派生函数(KDF)

VMess AEAD 模式使用基于嵌套 HMAC-SHA256 的 KDF:

KDF(key, path...):
    hmac_creator = HMAC(SHA256, "VMess AEAD KDF")
    for each p in path:
        hmac_creator = HMAC(hmac_creator, p)
    return hmac_creator(key)

KDF 的盐值常量(Salt Constants)如下表所示:

常量名
KDFSaltConstVMessAEADKDF "VMess AEAD KDF"
KDFSaltConstAuthIDEncryptionKey "AES Auth ID Encryption"
KDFSaltConstVMessHeaderPayloadAEADKey "VMess Header AEAD Key"
KDFSaltConstVMessHeaderPayloadAEADIV "VMess Header AEAD Nonce"
KDFSaltConstVMessHeaderPayloadLengthAEADKey "VMess Header AEAD Key_Length"
KDFSaltConstVMessHeaderPayloadLengthAEADIV "VMess Header AEAD Nonce_Length"
KDFSaltConstAEADRespHeaderLenKey "AEAD Resp Header Len Key"
KDFSaltConstAEADRespHeaderLenIV "AEAD Resp Header Len IV"
KDFSaltConstAEADRespHeaderPayloadKey "AEAD Resp Header Key"
KDFSaltConstAEADRespHeaderPayloadIV "AEAD Resp Header IV"

2.4 辅助函数

函数 说明
MD5(data) 输入任意长度字节数组,输出 16 字节
HMAC(H, K, M) H 为哈希函数,K 为密钥,M 为消息
Shake(data) SHA3-Shake128,输出任意长度字节流
FNV1a(data) 非加密哈希,用于数据完整性校验

3. 认证模式

VMess 协议头部支持两种认证模式,目前仅 AEAD 认证为推荐模式,MD5 认证已被废弃。

3.1 AEAD 认证(当前标准)

AEAD(Authenticated Encryption with Associated Data)认证通过 AES-128-GCM 对协议头部进行加密,能够同时保证机密性与完整性。

3.2 MD5 认证(已废弃)

MD5 认证使用 HMAC-MD5 + AES-128-CFB 对协议头部进行加密,无法保证头部完整性,存在重放攻击漏洞,已于新版本中移除。


4. 通信流程

VMess 是无状态协议,客户端与服务端无需握手即可直接传输数据。整体流程如下:

  1. 客户端构造请求,包含认证信息、指令段和数据段
  2. 服务端验证请求合法性
  3. 验证通过后,服务端转发请求至目标地址
  4. 服务端将响应数据返回给客户端

5. 客户端请求格式

5.1 AEAD 认证请求结构

+----------+---------------------------+--------------+---------------------------+------------------+
| EAuID    | ALength                   | Nonce        | AHeader                   | Data Section     |
| 16 bytes | 2 + 16 bytes (GCM Tag)    | 8 bytes      | variable + 16 bytes (tag) | remaining        |
+----------+---------------------------+--------------+---------------------------+------------------+

各字段说明:

  • EAuID:加密的认证 ID,用于标识用户身份
  • ALength:加密的指令段长度(2 字节明文 + 16 字节 GCM Tag)
  • Nonce:AEAD 加密的随机数
  • AHeader:加密的指令段
  • Data Section:实际传输的数据

5.2 EAuID(加密认证 ID)

EAuID 明文结构:

+------------------+-----------+----------+
| Timestamp        | Rand      | CRC      |
| 8 bytes (BE)     | 4 bytes   | 4 bytes  |
+------------------+-----------+----------+
  • Timestamp:64 位 Unix 时间戳(大端序)
  • Rand:随机数
  • CRC:CRC32([Timestamp, Rand]),使用 IEEE 多项式

EAuID 加密方式:

  • 加密密钥:KDF(CmdKey, "AES Auth ID Encryption")[:16]
  • 加密算法:AES-128 块加密(ECB 模式)

5.3 ALength 加密

ALength 使用 AES-128-GCM 加密:

  • 加密密钥:KDF(CmdKey, "VMess Header AEAD Key_Length", EAuID, Nonce)[:16]
  • Nonce:KDF(CmdKey, "VMess Header AEAD Nonce_Length", EAuID, Nonce)[:12]
  • 附加数据(AD):EAuID

5.4 AHeader 加密

AHeader 使用 AES-128-GCM 加密:

  • 加密密钥:KDF(CmdKey, "VMess Header AEAD Key", EAuID, Nonce)[:16]
  • Nonce:KDF(CmdKey, "VMess Header AEAD Nonce", EAuID, Nonce)[:12]
  • 附加数据(AD):EAuID

6. 指令段(Command Header)

指令段在 AEAD 和 MD5 两种认证模式下结构相同,仅加密方式不同。

+-----+--------+---------+---------+--------+----------+-----+---------+---------+-------+-------+
| Ver | BodyIV | BodyKey | RespHdr | Option | Security | Rsv | Command | Address | Pad   | FNV1a |
| 1B  | 16B    | 16B     | 1B      | 1B     | 1B       | 1B  | 1B      | var     | 0-15B | 4B    |
+-----+--------+---------+---------+--------+----------+-----+---------+---------+-------+-------+

各字段说明:

字段 大小 说明
Version 1 字节 固定为 0x01
Body IV 16 字节 数据段加密 IV,随机值
Body Key 16 字节 数据段加密密钥,随机值
Response Auth V 1 字节 随机值,服务端响应时必须回显
Option 1 字节 功能选项位掩码
Security 1 字节 高 4 位为填充长度 P,低 4 位为加密方式
Reserved 1 字节 固定为 0x00
Command 1 字节 0x01=TCP,0x02=UDP,0x03=Mux
Port 2 字节 目标端口(大端序)
Address Type 1 字节 0x01=IPv4,0x02=域名,0x03=IPv6
Address 可变 目标地址
Padding 0-15 字节 随机填充
Checksum 4 字节 FNV1a 哈希,覆盖指令段所有字段(不含自身)

6.1 Option 字段位掩码

说明
S 0x01 标准格式数据流(默认启用)
R 0x02 客户端期望复用 TCP 连接(已废弃)
M 0x04 启用元数据混淆(推荐)
P 0x08 全局填充,需 M 启用,且加密方式须为 AES-128-GCM 或 ChaCha20-Poly1305
A 0x10 启用认证包长度实验

6.2 加密方式编码

加密方式
0x01 Legacy(AES-128-CFB,已废弃)
0x03 AES-128-GCM
0x04 ChaCha20-Poly1305
0x05 None(无加密)
0x06 Zero(无加密无分块,原始流)

6.3 地址字段格式

  • T = 0x01(IPv4):4 字节 IPv4 地址
  • T = 0x02(域名):1 字节长度 L + L 字节域名
  • T = 0x03(IPv6):16 字节 IPv6 地址

7. 数据段格式

7.1 标准格式(Standard Format)

当 Option(S) 启用时,数据段采用分块传输格式,每个数据块结构如下:

+----------+------------------+----------+
| Length L | Data Packet      | Padding  |
| 2 bytes  | L-P bytes        | P bytes  |
+----------+------------------+----------+
  • Length L:大端序整数,最大值为 2^14(16384)
  • 当 Option(M) 启用时,实际长度 = 传输值 XOR Mask,Mask 由 Shake(Body IV) 生成
  • Padding P:当 Option(P) 启用时,P = ((RequestMask.NextByte() << 8) + RequestMask.NextByte()) % 64

7.2 各加密方式下的数据包格式

AES-128-GCM:

  • 密钥:指令段中的 Body Key
  • Nonce:count(2B) + Body IV[2:12],count 从 0 开始每包递增
  • 数据包 = (R-16) 字节实际数据 + 16 字节 GCM 认证标签

ChaCha20-Poly1305:

  • 密钥:MD5(Body Key) + MD5(MD5(Body Key))(扩展为 32 字节)
  • Nonce:count(2B) + Body IV[2:12]
  • 数据包 = (R-16) 字节实际数据 + 16 字节 Poly1305 认证标签

AES-128-CFB(已废弃):

  • 整个数据段使用 AES-128-CFB 加密
  • 数据包 = 4 字节 FNV1a 哈希 + (R-4) 字节实际数据

Zero 模式(0x06):

  • 强制使用基本格式,不进行任何加密
  • 协议头部仍使用 AEAD 或 MD5 认证加密

7.3 传输结束信号

当 NoTerminationSignal 未设置时,客户端须在传输结束时发送一个空数据块(L=0 或仅含认证数据长度),以通知服务端传输结束。


8. 服务端响应格式

8.1 AEAD 认证响应

响应加密密钥和 IV 由请求的 Body Key/IV 派生:

Response Body Key = SHA256(Request Body Key)[:16]
Response Body IV  = SHA256(Request Body IV)[:16]

响应头部分为长度和内容两部分,均使用 AES-128-GCM 加密:

响应长度加密(2 字节 + 16 字节 GCM Tag):

  • 密钥:KDF(Response Body Key, "AEAD Resp Header Len Key")[:16]
  • Nonce:KDF(Response Body IV, "AEAD Resp Header Len IV")[:12]

响应内容加密:

  • 密钥:KDF(Response Body Key, "AEAD Resp Header Key")[:16]
  • Nonce:KDF(Response Body IV, "AEAD Resp Header IV")[:12]

8.2 响应头部结构

+----------+--------+---------+---------+---------+
| RespHdr  | Option | CmdID   | CmdLen  | CmdData |
| 1B       | 1B     | 1B      | 1B      | var     |
+----------+--------+---------+---------+---------+
  • RespHdr:必须与请求中的 Response Auth V 一致
  • Option:0x01 表示服务端准备复用 TCP 连接(已废弃)
  • CmdID:0x01 表示动态端口指令

8.3 动态端口指令

服务端可通过响应中的动态端口指令,通知客户端使用新端口进行通信:

+----------+-------+---------+-----------+-------------+-------------+
| Reserved | Port  | User ID | Alter ID  | User Level  | Valid Time T|
| 1B       | 2B    | 16B     | 2B        | 1B          | 1B          |
+----------+-------+---------+-----------+-------------+-------------+

Valid Time T 单位为分钟,超时后客户端须重新使用主端口。


9. 用户认证与重放防护

9.1 TimedUserValidator

服务端维护一个 TimedUserValidator,对每个入站连接执行以下操作:

  1. 遍历所有已知用户的 CmdKey,尝试 AES 解密 16 字节 Auth ID
  2. 验证 CRC32 校验和
  3. 验证时间戳是否在服务端当前时间 ±120 秒范围内
  4. 通过重放过滤器检查 Auth ID 是否已被使用

9.2 重放防护机制

VMess 实现了两层重放防护:

  • Auth ID 过滤器:维护 120 秒内的 Auth ID 记录,拒绝重复的 Auth ID
  • Session History:缓存 3 分钟内的 {user, bodyKey, bodyIV} 三元组,防止会话重放

9.3 行为种子(Behavior Seed)

服务端通过 HMAC-SHA256 + CRC64 对所有用户 ID 计算一个确定性的"行为种子",用于控制对非法连接的随机读取长度(drainer 模式),以防止主动探测攻击。


10. 安全性分析

10.1 已知漏洞:MD5 认证重放攻击(CVE 级别,已修复)

2020 年 5 月,研究人员发现 VMess MD5 认证模式存在严重的重放攻击漏洞,主要原因如下:

漏洞一:认证凭据可在有效期内重放

MD5 认证的 Authentication Credential 基于 HMAC-MD5(UserID, UTC Timestamp) 生成,有效期约为 ±60 秒。攻击者可在此窗口内重放合法客户端的认证凭据,绕过身份验证。

漏洞二:AES-128-CFB 不提供认证,MAC-then-Encrypt 设计缺陷

指令段使用 AES-128-CFB 加密,该模式不提供完整性保护。协议采用 MAC-then-Encrypt 机制,但由于 Margin P 字段(填充长度)未经认证,服务端必须先盲目信任 Margin P 的值,读取 P+4 字节后才能验证 Checksum(FNV1a MAC)。

攻击者可利用 AES-CFB 的流密码可塑性(malleability),通过修改密文中特定字节来枚举 Margin P 的所有 16 种可能值,从而构造出能被服务端接受的探测包,识别 VMess 服务端。

漏洞三:不一致的连接关闭行为

研究人员发现,服务端在不同错误类型下关闭连接的行为存在差异,攻击者可通过观察服务端的响应模式(连接立即关闭 vs. 等待更多数据)来识别 VMess 服务端。

修复措施:

  • 引入 AEAD 认证模式,使用 AES-128-GCM 对头部进行认证加密,彻底解决完整性问题
  • 在所有错误类型下统一使用随机长度的 draining 策略
  • 新版本(Xray-core)已完全移除 MD5 认证支持

10.2 TLS 指纹识别问题

早期 V2Ray 客户端在发送 TLS ClientHello 时使用硬编码的密码套件,导致 TLS 指纹极为罕见,可被 GFW 精准识别。后续版本通过使用 Go TLS 库的默认配置加以缓解,但指纹唯一性问题在部分场景下仍存在。

10.3 HTTP 伪装失败

V2Ray 的 HTTP 伪装模式存在以下问题:

  • 客户端和服务端仅在每个 TCP 连接的第一个数据包中添加 HTTP 头部,后续数据包不含 HTTP 头部,流量特征明显
  • 服务端对各类错误统一返回硬编码的 500 响应,易被主动探测识别

10.4 AEAD 模式的安全性

当前 AEAD 认证模式在以下方面提供了较强的安全保证:

  • 机密性:AES-128-GCM 加密,密钥通过 KDF 派生,不可逆
  • 完整性:GCM 认证标签覆盖头部和数据,任何篡改均可被检测
  • 重放防护:EAuID 中的时间戳 + 随机数 + CRC32 三重校验,配合服务端 120 秒滑动窗口过滤
  • 前向安全性:每个会话使用随机生成的 Body Key 和 Body IV,即使长期密钥泄露,历史会话数据仍安全
  • 抗探测性:行为种子机制使服务端对非法连接的响应行为随机化,难以通过主动探测识别

11. 流量混淆机制

11.1 元数据混淆(ChunkMasking)

当 Option(M) 启用时,数据块的长度字段通过 SHAKE128 流进行 XOR 混淆:

RequestMask  = Shake(Request Body IV)
ResponseMask = Shake(Response Body IV)
wire_length  = actual_length XOR (Mask.NextByte() << 8 | Mask.NextByte())

此机制使流量的块长度分布更加随机,增加流量分析难度。

11.2 全局填充(GlobalPadding)

当 Option(P) 启用时,每个数据块后附加 0-63 字节的随机填充:

P = ((RequestMask.NextByte() << 8) + RequestMask.NextByte()) % 64

填充字节由 SHAKE128 流生成,增加流量的随机性。

11.3 认证包长度实验(AuthenticatedLength)

当 Option(A) 启用时,数据块的长度字段本身也使用 AEAD 加密:

length_key = KDF16(Body Key, "auth_len")

此特性进一步防止攻击者通过观察包长度分布来分析流量。


12. 传输层支持

VMess 协议本身工作在应用层,可运行于多种传输层之上:

传输方式 说明
TCP 原生支持,最基础的传输方式
WebSocket 通过 HTTP Upgrade 建立,可穿透 HTTP 代理
HTTP/2 基于 h2 协议,支持多路复用
gRPC 基于 HTTP/2,具有更好的穿透性
QUIC 基于 UDP,低延迟
mKCP 基于 UDP 的 KCP 协议,改善弱网性能
UNIX Socket 本地进程间通信

VMess over TLS(如 VMess+WebSocket+TLS)是常见的部署方式,通过 TLS 层提供额外的流量伪装,使流量看起来与正常 HTTPS 流量相似。


13. Mux 多路复用

VMess 支持通过 Mux(多路复用)在单个 TCP 连接上承载多个虚拟连接,以减少 TCP 握手开销。Mux 连接通过虚拟域名 v1.mux.cool 标识,UDP 流量则通过 XUDP 帧格式封装。


14. 与同类协议的比较

14.1 VMess vs. VLESS

VLESS 是 VMess 的后继协议,于 2020 年引入,主要改进如下:

特性 VMess VLESS
内置加密 是(AES-128-GCM 等) 否(依赖传输层 TLS)
协议开销 较高(双重加密) 较低(无冗余加密)
认证机制 UUID + AEAD UUID(简化)
设计复杂度 较高 较低
适用场景 无 TLS 场景 配合 TLS/XTLS 使用

当 VMess 运行于 TLS 之上时,存在双重加密(VMess 加密 + TLS 加密),造成不必要的 CPU 开销。VLESS 通过去除内置加密层,将加密职责完全交给传输层 TLS,显著降低了延迟和 CPU 消耗。

14.2 VMess vs. Shadowsocks

特性 VMess Shadowsocks
协议设计 复杂,功能丰富 简单,轻量
认证方式 UUID + AEAD 预共享密钥
混淆能力 内置多种混淆选项 依赖插件(obfs 等)
传输层支持 多种 主要为 TCP/UDP
抗重放 AEAD 模式下较强 依赖实现

14.3 VMess vs. Trojan

Trojan 通过完全模拟 HTTPS 流量来规避检测,而 VMess 依赖自身的加密和混淆机制。Trojan 在流量伪装方面更为彻底,但灵活性不如 VMess。


15. 协议演进

版本/阶段 主要变化
早期版本 MD5 认证 + AES-128-CFB,存在重放漏洞
v4.23.4+ 修复 TLS 指纹问题,使用 Go TLS 默认配置
AEAD 引入 新增 AEAD 认证模式,解决头部完整性问题
Xray-core 完全移除 MD5 认证,仅支持 AEAD;引入 XTLS、REALITY 等新特性
当前状态 VMess AEAD 为稳定协议,新项目推荐使用 VLESS+XTLS/REALITY

16. 总结

VMess 协议是代理协议设计领域的重要实践,其 AEAD 认证模式在机密性、完整性和抗重放方面提供了较为完善的安全保证。协议的分块传输、元数据混淆和全局填充机制有效增加了流量分析的难度。

然而,VMess 的设计复杂性也带来了一定的实现风险,历史上的 MD5 认证漏洞表明,协议设计中的细微缺陷可能导致严重的安全问题。随着 VLESS、XTLS 和 REALITY 等更新协议的出现,VMess 在新部署场景中的使用逐渐减少,但其设计思路和安全机制对后续协议的发展具有重要的参考价值。


参考资料