缓存与传输层指纹
传输层特征的保留仅在启用缓存的HTTPS连接内自动进行。没有缓存后缀时,Litport会让CONNECT保持不透明,且不会终止客户端的TLS连接。启用缓存模式后,Litport会尝试在发往源站的未命中和绕过缓存请求上复现受支持的指纹结构;不受支持的输入则改用一个经过验证的标准TLS配置。缓存命中完全不会建立到源站的连接。
此功能可减少HTTPS拦截带来的传输层差异。它不会冒充其他客户端:curl仍是curl,Chrome仍是Chrome,移动应用保留Litport实际从该应用观察到的兼容特征。
具体何时生效#
现有的密码后缀同时启用缓存和传输层结构保留:
PASSWORD_cache-images,fonts
PASSWORD_cache-all_cacheduration-30
满足以下所有条件时,Litport会尝试保留:
- 客户端使用Litport HTTP代理端点,并为HTTPS目标发送
CONNECT。 - 密码包含有效的缓存后缀,且认证成功。
- 节点的缓存和证书颁发机构均已就绪,因此Litport接受缓存拦截。
如果密码没有缓存后缀,CONNECT隧道保持不透明。Litport转发客户端的TLS记录和加密的HTTP字节,不读取也不改写。“不变”指的是经过Litport的应用层传输:目标仍会看到所选的代理出口IP及该出口的TCP/IP行为,而不是客户的本地网络身份。
如果在CONNECT开始之前无法接受缓存拦截,Litport会保持现有的不透明路径。普通HTTP目标、SOCKS5入口和HTTP/3/QUIC不适用此功能。
传输过程中发生了什么#
启用缓存的CONNECT包含两个相互独立的TLS连接:
client ── TLS leg 1 ──> Litport hub ── TLS leg 2 ──> verified HTTPS origin
Litport CA cache public Web PKI
实现按以下顺序处理:
- 观察ClientHello。一个有界的、仅在内存中运行的观察器会跨TLS记录重新组装第一条TLS握手消息,同时将原始输入原样传给经过验证的标准TLS协议栈。捕获的字节仅存在于该CONNECT内部,绝不会用作加密材料。
- 完成客户端握手。客户端验证由Litport缓存CA签发的目标证书。Litport验证TLS SNI与已认证的CONNECT目标地址一致。
- 安全地解析HTTP。协商得出的ALPN会选择入站的HTTP/1.1或HTTP/2服务端。有界观察器只保留复现所需的顺序和连接设置。
- 检查本地缓存。命中时立即返回。该次命中没有源站套接字、ClientHello、HTTP请求,也没有目标端的指纹。
- 保持所选路由。未命中或被拦截的绕过请求,会通过已为该请求选定的同一条Litport路由、产品、代理池、地理位置和计量路径连接源站。保留机制绝不会绕过代理,自行进行直接的DNS路由。
- 创建全新的源站TLS连接。Litport会清理观察到的配置,生成新的加密值,验证源站主机名和证书链,并提供兼容的、已观察到的协议。源站的ALPN结果决定在同一条活动连接上使用HTTP/1.1还是HTTP/2。
- 序列化请求。Litport输出受支持的HTTP结构,以流方式传输请求体和响应体,并应用常规的缓存规则和解码后字节的计量规则。
原始ClientHello、头部块、JA3/JA4值以及按客户端区分的配置标识符,均不会写入持久化存储或运行日志。
哪些会被保留,哪些必须是全新的#
TLS ClientHello结构#
对于受支持的ClientHello,Litport会保留兼容的可观察结构,例如:
- 协议版本和密码套件的顺序;
- 扩展的顺序以及安全且兼容的扩展内容;
- 支持的组、签名算法、点格式和ALPN的顺序;
- key share组的顺序、证书压缩选项、GREASE位置以及兼容的填充。
每个源站连接都会获得全新的client random、session ID和key share。Litport会移除PSK identity和binder,仅在原先存在该扩展时保留一个空的session ticket提议,并且不会重放early data、TLS cookie或其他与连接绑定的内容。GREASE ECH占位符会在相同位置安全地重新生成;真实的ECH载荷不会被重放。默认拒绝不透明的扩展;经过审查的例外是常见curl构建所使用的那一对空的、无状态的OpenSSL扩展。
HTTP/1.1结构#
Litport会保留经代理清理后仍然存在的字段的顺序和原始大小写,包括重复字段的位置。仅供代理使用的凭证始终会被移除。消息分帧是根据已解析的消息体重新构建的,因此即使可以保留其观察到的位置和大小写,Content-Length或Transfer-Encoding仍然有效。仅由HTTP解析器添加的字段不会被误认为客户端输入,也不会作为结构的一部分被转发;客户端未发送时,Litport也不会添加默认的User-Agent。
协议升级、Expect: 100-continue、格式错误的分帧,或观察器与解析器不一致时,会使用确定性的标准HTTP序列化。它们不会导致Litport在CONNECT进行到一半时更换TLS配置。
HTTP/2结构#
Litport会保留受支持的初始SETTINGS的顺序和取值、连接级WINDOW_UPDATE的行为、请求前的PRIORITY帧、每个请求的HEADERS优先级、伪头部顺序以及常规字段顺序。单个Cookie字段仍保持为一个字段,而不会按分号拆分;原本不存在的User-Agent仍保持不存在。没有请求体的请求在其初始HEADERS帧上结束,而不会额外多出一个合成的空DATA帧。请求元数据按流隔离,因此并发请求无法借用其他流的结构。
精确的HPACK字节和动态表历史不在兼容性承诺范围内。响应、缓存命中、并发和连接复用会使两个压缩历史出现差异,即使相同的字段以相同的顺序出现。
实现边界#
保留状态只属于一个已认证的CONNECT。它绝不会在客户、令牌、目标地址或之后的客户端连接之间共享。
| 阶段 | 边界与生命周期 | 如果无法安全地复现所观察到的内容 |
|---|---|---|
| ClientHello | 最多64 Ki |
该CONNECT使用一个经过验证 |
| HTTP/1.1请求观察 | 活动的头部或尾部块最多72 Ki |
在已选定的TLS身份上使用确定性 |
| HTTP/2连接观察 | 从客户端前导(preface)到 |
在已选定的TLS身份上使用确定性 |
| 源站连接 | 由当前CONNECT独占的HTT |
CONNECT结束时关闭连接池; |
对于HTTP/1.1,观察器会跟踪定长和分块的消息体(包括尾部字段),因此消息体内的字节不会被误认为下一个流水线请求。在应用观察到的字段序列之前,Litport会将方法、请求目标以及规范化的字段和取值数量与已解析的请求进行比对。无论代理认证字段出现在什么位置,都会被移除。
对于HTTP/2,Litport结合了两种视角。帧级观察器捕获初始SETTINGS、连接级WINDOW_UPDATE以及请求前的PRIORITY帧。HTTP/2解码器仅将当前流的伪头部顺序、常规字段顺序和HEADERS优先级附加到该请求的内存上下文中。随后,源站侧传输层在对应的流上使用这些值,从而防止并发请求借用彼此的顺序或优先级。
客户端CONNECT结束时,Litport会关闭协议连接池及其持有的每个原始源站套接字。这同样会终止仍在收尾最后一个流的HTTP/2读取循环;它不会继续存活,也不会被后续的CONNECT使用。
源站套接字始终通过Litport已选定的上游路由打开。主机名和公共证书链的验证保持开启。HTTP引擎是根据该套接字上源站返回的ALPN结果选择的;Litport不会仅为了获得偏好的协议而重新连接。如果HTTP/2客户端访问仅支持HTTP/1.1的源站,该请求会使用保持字段顺序的HTTP/1.1。
为什么不可能得到完全相同的指纹#
TLS拦截无法逐字节保留完整的连接。对客户端而言,Litport是一个TLS服务端;对目标而言,Litport是另一个独立的TLS客户端。在第二条连接上重用第一条连接的机密既无效也不安全。
以下内容必然不同,或可能出现差异:
| 特征 | 为什么不能相同 |
|---|---|
| TLS random、key share、binder和tra |
它们在密码学上绑定于某一次握手。 |
| Session ticket、PSK identity和0-RTT | 为客户端到Litport这一段签 |
| 服务器证书和Server |
客户端看到的是Litport签发 |
| TCP SYN、源地址和操作系统协议栈 | 到目标的连接来自所选的代理出口。 |
| TLS记录、数据包大小和时序 | 缓冲、路由、缓存查找、调度和网络 |
| HTTP |
命中会使请求不再经过到源站的链路 |
因此,如实作出的保证是兼容的传输层指纹结构保留,而不是完整的指纹保留。它针对的是JA3、JA4和HTTP/2指纹识别通常使用的稳定特征,同时让所有与连接绑定的内容保持全新。
回退与失败规则#
安全优先于相似性:
- 受支持的捕获会为属于该客户端CONNECT的每个源站连接使用经过清理的、保留下来的TLS配置。
- 过大、格式错误或不安全的ClientHello会在整个CONNECT期间使用经过验证的标准TLS配置。Litport绝不会在同一条客户端隧道内交替使用两种TLS身份。
- 特定于请求的HTTP元数据可以回退到确定性的标准序列化,而不会更改该CONNECT所选的TLS配置。
- 如果采用保留配置的源站握手已发送字节后失败,Litport会返回源站错误。它不会用相互矛盾的ClientHello重试,也不会削弱证书验证。
- 每次与源站建立连接都仅限于已认证的CONNECT目标地址,并且仍使用所选的上游路由。
客户可以在“流量统计”和令牌API中看到缓存命中、未命中和绕过缓存,以及免费字节数和节省金额。传输层保留没有面向客户的逐请求状态。
客户端与协议行为#
| 客户端或协议 | 启用缓存后的行为 |
|---|---|
| curl、SDK和命令行客户端 | 当该进程信任Litport缓存根 |
| Chrome、Firefox和浏 |
可以保留HTTP |
| 自己控制的Android和i |
当应用实际生效的信任配置接受Li |
| 使用证书固定的应用 | 缓存拦截按设计会失败。移除缓存后 |
| 真实的ECH | 其加密载荷绑定于原始服务器配置, |
| HTTP/3/QUIC | 不属于TCP CONNECT缓存路径。应用可能 |
| 普通HTTP和SOCKS5 | 此功能绝不会拦截它们。它们保持现 |
各客户端的信任设置说明,参见证书设置。
使用指纹端点验证#
如需进行可选的外部检查,通过同一节点分别发出一个不透明请求和一个启用缓存的被拦截请求。下面的端点会返回JA3、JA4、HTTP/2和TCP的观测结果:
# Opaque: Litport does not terminate TLS
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD' \
'https://tls.peet.ws/api/all'
# Intercepted bypass: extensionless diagnostic URL is not stored, but transport preservation runs
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-images' \
--cacert litport-cache-root.crt \
'https://tls.peet.ws/api/all'
# A second independent JA3/JA4 and HTTP/2 view
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD' \
'https://tls.browserleaks.com/json'
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-images' \
--cacert litport-cache-root.crt \
'https://tls.browserleaks.com/json'
比较tls.ja3_hash、tls.ja4、有序的TLS字段以及HTTP/2指纹。不要比较client_random、session_id、源IP、TCP指纹或时序;这些预计会发生变化。在BrowserLeaks的响应中,对应的字段是ja3_hash、ja4和akamai_hash。这是第三方诊断服务,因此它会看到代理出口IP和请求元数据。仅在可以接受这种披露时才使用它。
延伸阅读#
Litport博客文章通过代理进行TLS指纹识别:JA3和JA4说明了不透明隧道、拦截代理和缓存模式各自如何影响JA3、JA4和HTTP/2指纹,并给出了常见客户端的实测结果。