切换深浅色
第28章 Trojan:TLS里面的代理请求
28.1 真正使用TLS,不等于在TLS里面使用HTTP
Trojan把机密性、传输完整性和服务器证书认证主要交给标准TLS,代理协议本身负责发送凭据、命令、目标及数据。正常路径先完成与代理服务器的TLS握手,再在TLS Application Data中发送Trojan请求。它不是用几字节假TLS头装饰明文,也不要求TLS内第一行是GET或CONNECT。
本章原始协议与实现固定于trojan-gfw/trojan提交3e7bb9aecdc694f9bcae8d646fae395f773d60f8(2020-11-08)。该时间是所读提交的时间,不表示本书把它称为2026新设计。Xray相关兼容行为仍固定于0888beb38a9ba45440557175e71ce21cf8ba3b13。两者的解析宽严、回退与承载扩展分别注明。
客户端首先拨号代理端点,完成TLS服务器认证;服务端持有证书与对应私钥,建立TLS会话后读取解密字节。网站TLS若也存在,则又是一套独立会话:浏览器的网站ClientHello作为Trojan负载被转发,代理并不因为终结外层TLS就取得网站的应用流量密钥。
text
客户端到代理的TCP:
外层TLS记录[Trojan头 || 网站TLS记录[网站握手或加密HTTP]]
代理到网站的TCP:
网站TLS记录[网站握手或加密HTTP]外层TLS的证书名称属于代理服务器,内层证书名称属于目标网站。即使两个连接都用443端口,验证输入也不能互换。客户端信任某代理域名的证书,不代表浏览器应接受该证书充当example.com的网站证书。
原始客户端实现可以设置SNI,并根据verify和verify_hostname等配置启用证书链与名称验证。SNI负责告诉对端期望哪个名称,它本身不是服务器身份证明。发送了正确SNI而关闭验证,攻击者仍可能建立另一条TLS并读取Trojan凭据;是否存在TLS加密与是否认证了预期端点必须分别判断。
同样,Trojan头没有独立的完整AEAD记录层,不能脱离安全承载就宣称有同样保护。某些软件允许在私有链路、外部安全终结或其他包装中使用它的解密格式;这属于具体架构。固定Xray对公共Trojan端点也有无额外安全层的配置限制,不能据其内部ConnWriter只写字节,就说标准Trojan在公网本来无需TLS。
外层TLS能提供何种PFS、算法与恢复性质,取决于实际协商和配置。现代TLS1.3临时密钥交换与第16章所述条件相关,而协议名Trojan本身不强制证明每个历史实现都选用了TLS1.3,也不额外加入后量子交换。不能把“使用真实TLS”扩大成所有会话都有相同安全属性。
初始Trojan请求通常可在TLS握手后直接发送,无需再等待一份专用代理认证挑战。远端校验后建立目标连接,返回字节由TLS保护。减少额外挑战步骤的代价之一,是凭据本身成为可重复使用的值;下一节将解释它为何不能简单理解为“发送散列就不泄漏密码能力”。
TLS承载说明见固定官方protocol.md,客户端连接与验证见clientsession.cpp和service.cpp,Xray出站安全检查见infra/conf/xray.go。
28.2 SHA224后的56字符仍是一份可使用凭据
Trojan请求最前面发送hex(SHA224(password))。SHA224输出224位,即28字节;每字节写成两个小写十六进制ASCII字符,最终在线上TLS解密流中占56字节。它不是发送原始28字节散列,也不是对56个十六进制字符再做一次散列。
例如公开教学口令abc对应:
text
23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7这里的开头23是两个ASCII字符,其实际字节为32 33;它不等于单字节23。服务端按同样规则处理配置口令,并比较收到的凭据。固定Xray的MemoryAccount.Key保存的正是56字节文本,ConnWriter直接把它写入请求。
这样做没有把口令变成挑战响应。客户端每次发送同样凭据,协议头没有为该散列加入服务端随机挑战、时间戳或独立Nonce。任何取得这56字节且能连接入口的人,都可以把它用于构造新请求,不必先反推出原始口令。因此从代理认证能力看,它是口令等价材料,保护它与保护口令同样必要。
要区分两种“重复”。把网络上捕获的TLS密文记录原封不动塞入另一条新TLS连接,通常不会通过新会话的密钥、序号与Tag检查;但在TLS终结点取得56字节明文凭据,再通过新的合法TLS连接发送,就不需要重用旧密文。TLS防止前一种记录挪用,并不替Trojan把后一种静态凭据改造成一次性令牌。
SHA224也不是慢速口令派生函数。若攻击者得到这份散列,可以对猜测口令快速做SHA224并比较。没有每次认证的随机挑战,并不表示所有旁观者都已看到散列;正常已认证TLS能保护其运输。应分别判断“谁能够接触解密内容”和“接触后凭据有什么作用”。
| 材料 | 能承担的作用 | 不能由它单独证明的事 |
|---|---|---|
| 原始口令 | 计算静态Trojan凭据 | 服务器TLS身份 |
| 56字符摘要 | 直接作为代理认证输入 | 这次请求是新鲜、未被持有者再次发起 |
| 外层TLS会话密钥 | 保护当前连接记录 | 目标网站证书可信 |
| 网站TLS密钥 | 保护浏览器与网站的应用记录 | 代理入口账号授权 |
若多名用户共用同一口令,服务端也无法仅凭这个摘要区分他们。多用户实现可以保存多份不同凭据并关联配额或标签,但摘要自身没有匿名凭证或数字签名的性质。它证明的最多是请求者具备可接受凭据,而不是不可转移的个人身份。
PFS应回到TLS分析。正确使用临时交换的TLS会话可以让后来泄漏的服务器证书私钥不直接恢复过去TLS记录;Trojan的静态摘要没有破坏这个密钥依赖,也没有另行创造PFS。但若过去明文摘要已从终结点泄漏,它可作为后续代理认证输入,这是另一个时间和攻击位置的问题。
原始格式及固定Xray的散列生成见官方protocol.md、config.go与protocol.go。公开abc仅作编码示例,不是本书提供的实际凭据。
28.3 CRLF与二进制地址:一个混合格式的头
Trojan请求由56字节摘要、CRLF、命令及目标、第二个CRLF组成,后面直接接负载。CRLF是0d 0a两个字节,用于结构分隔,并没有把整个协议变成HTTP:命令、地址类型、长度和端口仍是二进制字段。
text
摘要ASCII56 || 0d 0a || CMD1 || ATYP1 || 地址 || 端口2大端 || 0d 0a || 负载CMD01表示TCP CONNECT,03表示UDP ASSOCIATE。这个03不是VMess/VLESS的UDP02;同样的命令名称不保证取值一致。地址类型按SOCKS5:IPv401、域名03、IPv604。域名包含1字节字节数前缀,IPv4/IPv6则由类型确定地址长度。线上没有SOCKS5的版本05、方法列表或额外RSV字段。
以example.com:443的TCP请求为例,字段位置如下:
| 偏移 | 长度 | 内容 |
|---|---|---|
| 0—55 | 56 | 小写十六进制ASCII摘要 |
| 56—57 | 2 | 0d 0a |
| 58 | 1 | 01:TCP命令 |
| 59 | 1 | 03:域名类型 |
| 60 | 1 | 0b:域名11字节 |
| 61—71 | 11 | example.com |
| 72—73 | 2 | 01 bb:443 |
| 74—75 | 2 | 0d 0a |
| 76起 | 可变 | 目标协议字节 |
头共76字节。IPv4头为68字节,IPv6头为80字节;域名头一般为65加域名字节数。这个开销包含认证摘要,但不含TLS记录或TLS握手,也不含网站协议负载。
接收器不能只搜索第二个CRLF就认定头结束。二进制IPv4、IPv6、端口等字段中也可能出现0d 0a组合;必须先依类型、长度和字段位置解析,再检查规定分隔符。首个摘要只包含十六进制ASCII,后续二进制部分却没有这种字符集合保证。
TCP仍可以把76字节头拆在多个读取中,或把头与网站ClientHello合并交付。规范鼓励首批头和负载一起发送以减少可识别的单独短写,但它不提供“首个TCP段一定包含完整头”的契约。TLS记录边界也与Trojan头边界独立;TLS可以把多段应用写入组合或拆开。
解析宽严要按实现注明。所列原始TrojanRequest::parse检查命令是否为CONNECT或UDP ASSOCIATE,并检查地址之后的CRLF。固定Xray的ConnReader.ParseHeader则按固定长度读取两个分隔位置,未在该函数逐字节核对它们等于0d 0a;命令03选UDP,其余值在这个函数走TCP。上层还另有账号与首读检查,因此不能把局部函数单独当作整个入口的全部验证。
这不是说发送端可以把任意分隔符或命令当成标准。互操作应按官方格式生成;宽松接收只是所列代码路径的行为,另一实现完全可能拒绝。同样,不能在讲规范时写成“所有实现遇到CRLF不符都会立即拒绝”,因为所读路径并非如此。
普通TCP回程不再发送另一份Trojan成功头。服务器连到目标后,目标字节经外层TLS返回客户端;没有像SOCKS5那样固定的REP,或VLESS默认00 00响应。目标连接失败如何关闭及浏览器如何显示,依实现和上下游协议处理,不能凭空插入HTTP 200作为Trojan认证成功标记。
规范及严格生成见固定protocol.md与trojanrequest.cpp,Xray的写读差异见protocol.go,入口前置检查见server.go。
28.4 TCP是连续流,UDP要在流里重新定界
TCP命令之后,Trojan不再为每个应用Write加自己的长度字段。后续内容是连续字节流,TLS负责安全记录,TCP负责有序运输,目标协议决定自己的消息边界。一个网站HTTP响应可能跨越许多TLS记录和读取,代理不应把这些边界改成HTTP消息的结束标记。
UDP命令则不同。客户端与Trojan服务器之间仍是TLS保护的流,而服务器与各目标之间要发送独立UDP数据报。于是必须在流里编码每个UDP包的目标和长度,远端才能恢复数据报边界。
text
ATYP1 || 地址 || 端口2大端 || Length2大端 || 0d 0a || Payload[Length]这里Length只数UDP应用负载,不含地址头、它自己和CRLF。一个包的目标之后还可以跟另一个包,不能把一次TLS记录或Socket.Read的长度当成Length。UDP回程也使用相同帧结构,地址语义表示返回数据所关联的源/目标端点,客户端据此还原本地UDP转发结果。
例如向example.com:53发送hello这个仅用于长度说明的5字节负载,帧为24字节:
text
03 0b 65 78 61 6d 70 6c 65 2e 63 6f 6d 00 35
00 05 0d 0a 68 65 6c 6c 6f前15字节是域名地址与端口,后面4字节为长度和CRLF,最后5字节是负载。hello不是合法DNS请求,本例只说明UDP帧编码,不声称目标DNS服务器会返回答案。外层还须先有一次Trojan认证及UDP ASSOCIATE请求,不能把这24字节单独作为完整新连接发送。
初始UDP ASSOCIATE头里也有地址字段,但每个UDP帧再次携带地址,实际目标应按帧处理。固定Xray在识别UDP关联后进入PacketReader/PacketWriter与UDP分发器,读取每帧地址,再转发其负载。不能因为最初关联头填写了一个端点,就把后续所有包强行解释为那个端点而忽略帧内地址。
固定PacketReader将Length读为uint16,却明确拒绝大于8192的负载。这个8192是所列实现路径的限制,不能把字段理论容量65535当成该路径全部可用容量。发送侧的内部Buffer也有空间约束。原始实现又有自己的缓冲与解析方式,因此协议说明、软件上限及实际路径MTU要分别读取。
UDP装进TCP会改变丢包行为。客户端到代理这段只要某个TCP区间缺失,后续UDP帧即使已随更晚TCP段到达,也要等TCP补齐才能交付。它能避免这一段由应用直接观察到某些单包丢失,却可能增加实时等待;到目标的UDP段仍然会丢包,也没有由Trojan统一提供端到端可靠交付确认。
例如包A和包B属于两个独立语音时刻,B已经没有补到A之后再播放的价值,TCP仍会维护流顺序。相反,某些UDP应用宁愿等待以穿过只允许TCP/TLS的网络。两者是应用需求与网络约束的取舍,不能把“UDP经过TLS”自动列为更可靠且更低延迟。
TCP/UDP目标转发仍由服务器执行。外层TLS保护客户端到服务器,服务器解开后可读UDP负载,除非负载自身还有加密。使用UDP命令没有让代理变成看不懂目标的透明加密交换点,也不把所有UDP协议都自动变成网站TLS。
UDP帧规范见固定protocol.md及udppacket.cpp;Xray的长度限制及逐帧转发见protocol.go和server.go。
28.5 回退发生在TLS之后:另一条解密数据路径
Trojan入口面对的客户端未必发送Trojan。普通浏览器也可能先完成TLS,再发一份HTTP请求。若直接因缺少代理凭据而立即返回显眼的错误,入口行为就与普通网站不同。原始设计允许把不属于有效Trojan的解密内容交给预先配置的后端,让后端处理普通网站请求。
这个回退不是把客户端原始TLS握手转给后端。TLS已经由Trojan服务器终结,后端通常得到的是TLS解密后的HTTP字节。例如浏览器发来的GET / HTTP/1.1,经过入口解密后交给本机HTTP服务;服务返回HTTP响应,由入口重新通过同一外层TLS发回浏览器。
正在绘制图表…
查看图表原文
sequenceDiagram
participant C as 普通浏览器或探测连接
participant T as Trojan入口
participant H as 配置的回退HTTP后端
C->>T: TCP与TLS握手
T-->>C: 入口自己的证书与TLS握手
C->>T: TLS内发送HTTP请求
T->>T: 解密后未匹配Trojan凭据/结构
T->>H: 转发已解密的原始HTTP字节
H-->>T: HTTP响应明文
T-->>C: 同一TLS会话保护的HTTP响应
后端看到的不是浏览器与它直接建立的TLS会话,也不会因为入口证书可信就自动有到后端的加密。若后端在同机回环地址,信任边界相对局部;若跨主机,解密内容的运输和后端认证需要另外安排。把回退位置写成远程地址,并不会自动继承入口那条TLS的保护。
所列原始ServerSession先解析初始解密数据,匹配口令;有效请求转到用户指定目标,其他输入按配置remote_addr/remote_port或相关ALPN覆盖选择回退目标,并保留原始数据供后端处理。入口仍掌握证书与私钥,网页后端并未把自己的TLS私钥交给入口动态使用。这与第21章REALITY中的专用握手及非认证转发不属于相同机制。
Xray实现的fallbacks可以按名称、ALPN和有限的路径检查选择后端,但不能把这些检查当作完整HTTP代理解析器。它只在特定首批检查失败路径触发:首读少于58字节、索引56不是回车或账号查找失败,可以设置shouldFallback;若没有配置fallbacks,则直接拒绝。通过前置账号检查后,后续ParseHeader失败会返回错误,不是所有解析错误都再进入回退。
首读条件还说明了一项实现约束:即使合法头最终有76字节,TCP也不保证首次Read提供58字节。TLS应用记录与缓冲方式可能影响这里的首批可读数据;一次读取较短时,所列路径可以回退或拒绝,而不是无限等到完整Trojan头。这个行为来自具体实现,不是TCP违反了字节流契约,也不是官方头长改变。
回退还可能把初始56字节摘要等输入交给后端。当客户端使用了错误口令却结构近似Trojan时,后端收到的并非正常HTTP请求。它可能返回错误、关闭或记录异常内容。凭据虽对代理无效,也可能在别处被复用;因此回退终结点属于会接触解密输入的信任范围,不能因其名叫“伪装网站”就排除在数据路径之外。
若启用PROXY protocol,入口还可能在转发字节前给后端添加来源元数据。后端须预期这份额外头,否则会把它误作HTTP或其他应用内容。它也不是Trojan请求中的用户认证字段,而是入口与后端之间另约定的连接元数据。
回退能够提供某种正常网站响应,不证明所有主动探测、错误时序、TLS指纹及长度分布都与一个特定网站完全一致。官方文档里的不可识别目标应与可验证机制分开;本书没有做覆盖所有探测的实验。更直接的部署约束是,普通HTTP CDN会解析HTTP,它无法仅靠终结TLS就自动理解有效Trojan的二进制请求。要经HTTP入口承载它,须有明确支持的额外封装与两端实现。
原始回退控制见固定serversession.cpp;Xray首读判断、回退选择与原始字节转发见server.go。
28.6 完整81字节请求与TLS记录开销
继续使用公开教学口令abc、目标example.com:443与负载hello。下面展示的是外层TLS解密后的完整Trojan请求,不是真实网络抓包,也不表示hello是该网站443端口接受的应用协议。摘要按28.2节复算,字段按28.3节组织。
text
0000: 32 33 30 39 37 64 32 32 33 34 30 35 64 38 32 32
0010: 38 36 34 32 61 34 37 37 62 64 61 32 35 35 62 33
0020: 32 61 61 64 62 63 65 34 62 64 61 30 62 33 66 37
0030: 65 33 36 63 39 64 61 37 0d 0a 01 03 0b 65 78 61
0040: 6d 70 6c 65 2e 63 6f 6d 01 bb 0d 0a 68 65 6c 6c
0050: 6f前56字节看起来像一串十六进制数字,但在这张表里已经再次转换为字节值。例如摘要末尾da7是64 61 37三个ASCII字节;紧接着偏移56的0d 0a才是结构分隔符。偏移58为TCP命令01,59为域名类型03,60为域名长度0b,76开始的68 65 6c 6c 6f才是应用内容。
服务端若首次读到整份81字节,前置识别后ParseHeader消费76字节,余下5字节由同一个缓冲Reader继续提供给目标连接。不应把首读缓冲已经包含的hello丢弃,再从Socket等待“下一份负载”。这与第19章分析的头后剩余字节处理是相同的流解析要求。
若只先读到60字节,服务端已经有账号材料和命令/地址类型,但域名长度及地址还未收齐,后续解析可以继续等待。若首次读得少于58字节,则所列Xray入口会走28.5节的回退或拒绝判断。二者不同来自前置首读策略,而不是报文本身在60字节处分出了另一个逻辑消息。
假定外层为TLS1.3、使用16字节AEAD Tag、不加TLS内Padding,并且81字节正好放入一个应用记录,则记录明文还要增加1字节内部内容类型,密文长度为98,外加5字节记录头共103字节。可见记录头会是17 03 03 00 62;后面的98字节依实际TLS密钥和序号计算,本书没有为这次假定连接编造它们。
如果Trojan头76字节单独形成一个TLS记录,再把hello5字节形成另一个,分别占98与27字节,合计125。它比合并情况多22字节,是多一个TLS1.3记录的条件性差额。真实TLS实现会怎样合并或切分,必须按具体Write、缓冲与记录实现分析,不能从这个算术例认定每次请求恰好发103或125字节。
固定Xray客户端在ConnWriter外加BufferedWriter,先尝试一次最多100 ms的应用数据读取,再Flush;若头尚未发送,还会用一次空Write触发头。应用数据已可读时不必等满100 ms,Reader能力不同也有相应分支。它体现的是把头与首批负载合并的意图,不保证一个Write对应一个TLS记录或一个TCP段。
UDP可以用另一个同样清楚的计数:初始UDP ASSOCIATE头中命令换为03,之后28.4节24字节UDP帧各自重新定界。若初始目标仍使用这个11字节域名,单算Trojan明文为76+24=100字节;没有第二份56字节摘要。之后同一关联再发下一帧,也不每次重新发送初始认证头。外层连接断开重建,才需要重新建立TLS与Trojan请求状态。
这些数字只说明指定字段与记录条件下的开销,不比较AES吞吐或真实延迟。本例没有握手密文、生产密钥、目标响应或真实测量数据。结构及缓冲路径可对照固定protocol.go与client.go,TLS记录计数沿用第16章的结构规则。
28.7 与VLESS+TLS比较:安全承载相似,代理语义不同
在同样使用经验证TLS、同样连接目标、同样没有其他扩展的条件下,Trojan与VLESS+TLS都把代理请求放在外层TLS应用数据内。外层TLS终结于代理服务器,网站TLS若存在则继续终结于浏览器和网站。不能仅因一个叫密码、一个叫UUID,就把这两个完整组合判为不同级别的端到端保密。
它们首先不同在TLS解密后的代理头。Trojan发送56字符静态摘要、CRLF、SOCKS式命令和目标;基础VLESS发送版本、原始16字节用户标识、Addon、命令和另一套地址顺序。对example.com:443,无Addon VLESS请求头34字节,Trojan头76字节,两者都还要另计相同条件下的TLS记录与握手。
| 维度 | 原始Trojan正常TCP路径 | VLESS+TLS基础TCP路径 |
|---|---|---|
| 认证输入 | 静态SHA224摘要的56字节ASCII | 基础请求中的16字节用户标识 |
| 目标地址顺序 | 类型、地址、端口 | 端口、类型、地址 |
| 域名类型 | 03 | 02 |
| 返回开头 | 直接返回目标字节 | 版本与Addon长度等响应头,再返回目标字节 |
| 负载处理 | TCP通常连续流,由TLS保护 | 基础流由TLS保护,可选择相应扩展 |
| UDP命令与包边界 | 命令03,每帧含地址、长度、CRLF | 命令02及相应UDP数据结构;具体扩展另看 |
| 额外Flow | 原始协议没有Vision Flow | Addon可声明Vision,前提是实现与组合支持 |
静态摘要与UUID都是可使用的认证材料。泄漏其中一种后,攻击者可能通过新的合法TLS连接尝试代理认证;“摘要看起来更长”不能让它自动具备一次性或挑战响应性质。真正比较猜测成本,还需知道口令/UUID如何产生、是否被复用以及服务器策略。字符数量不是秘密熵的直接度量。
两种代理头通常都不额外执行一轮服务端挑战,所以在相同外层首次TLS握手后,都可以发送目标请求。Trojan没有基础VLESS响应头,不表示它就少等待了一次必需往返:VLESS的响应可以随返回字节发送,并不要求客户端先收该头才发网站ClientHello。报文数量、网络包数量和握手依赖不能相互替代。
Vision会改变比较前提。启用并触发它后,VLESS可能按第23章绕过某层外部记录与Padding,进入不同复制路径;原始Trojan没有这套命令、检测与双向切换。若第三方实现为Trojan增加特殊流控或传输扩展,应注明实现版本和协议变化,而不是把它直接归入原始Trojan的保证。
CDN条件也相同地需要拆层。普通L7入口理解HTTP,Trojan的原始二进制头与VLESS的基础二进制头都不是普通HTTP请求。额外WebSocket或XHTTP等承载可以提供HTTP外壳,但须查软件具体支持,以及终结TLS后能看到哪层内容。不能只凭两者都有TLS就宣称任意HTTP CDN均可接入。
性能分析应以最终路径为单位:代理头在短连接中较显著,长下载中则可能被摊薄;TLS实现、AEAD硬件、Body复制、目标延迟和连接复用可能成为更大因素。本章没有同条件测试数据,因此只给出头部和处理步骤差异,不给无依据的速度名次。
格式对照见固定Trojan protocol.go、VLESS encoding.go及Vision处理。
28.8 两种认证与两个安全终点
Trojan连接里至少有两个需要回答的问题:客户端连接的是否是预期代理服务器,以及服务器是否允许这个客户端使用代理。正常部署用TLS证书验证回答前者,用Trojan摘要凭据回答后者。任何一个成功都不能自动证明另一个成功。
TLS服务器可以持有合法证书,却不接受这份Trojan凭据;客户端也可以持有正确凭据,却因连到了错误或未认证端点而泄漏它。仅检查证书链而不核对名称、或只发送SNI不验证证书,都不能完整替代预期服务器认证。所列原始实现名称验证使用当时的库接口,具体名称规则应按对应库和版本理解,不把它当成现行所有TLS客户端共同的规则。
若前面另有TLS终结网关,网关将看到Trojan摘要及目标。它可以把解密流传到内网Trojan解析器,也可能重新建立另一条TLS,但信任终点已经从原来一台代理变成包含网关。两段分别加密不等于网关看不到中间明文。网站TLS仍可保留应用内容保密,却不会隐藏代理头里明示的目标。
回退分支也位于解密范围。后端可以看到未通过代理入口识别的输入,入口则读取这些输入来决定路径。能显示正常网页说明回退应用起作用,不能证明用户认证、防重放、DNS隐私或所有流量形状都已满足预期。ALPN显示h2也只代表相应TLS协商结果,不自动把有效Trojan负载变成HTTP/2帧。
TLS恢复与0-RTT还需另分。恢复一条TLS连接不等于延续原来已经打开的网站TCP会话;新连接仍需发送新Trojan头并建立相应目标。若某实现把静态Trojan头或应用数据放进TLS早期数据,必须处理第16章的0-RTT重放边界,不能靠“摘要已哈希”消除重复执行。这里是对采用早期数据的条件分析,不声称所列原始实现默认已经开启这种发送方式。
正常TLS记录提供序号和认证,但Trojan本身没有2022 Shadowsocks式时间戳和请求Salt缓存。因此它的静态凭据不证明请求新鲜性;原始客户端到代理的身份授权与具体TLS记录防篡改属于不同层。持有摘要的人重新发请求,和不知道密钥的人修改记录,面临的条件完全不同。
面对实际方案,可据完整路径作出判断:外层谁终结TLS、怎样验证服务器、谁能读到摘要、目标DNS由谁发起、UDP经过流还是数据报、回退把什么明文交给谁、网站是否还有自己的加密。只有这些答案明确后,TLS的PFS、代理授权、出口地址与流量外观才有各自准确的含义。
本章所读官方格式及源码证明的是其分层设计与具体处理,不是不可识别性或全软件安全证明。接下来分析QUIC代理时仍沿用这组问题,只是可靠流、数据报、认证入口和拥塞控制的安排会改变;底层从TCP换成UDP上的QUIC,并没有消除对这些职责的区分。
证据入口为固定官方TLS与验证配置、官方请求/回退分流和Xray入口处理。