mihimo 为各类协议添加了 JLS camouflage

来源: https://wiki.metacubex.one/config/proxies/tls/#jls-opts

去年发的时候是 shadowquic 协议带着 JLS camouflage 出现


mihomo 为 snell 、anytls 、trjon、 vless、ss、vmess 协议都实现了 JLS camouflage

以anytls配置为例 https://wiki.metacubex.one/config/inbound/listeners/anytls/

  # jls-config: # JLS 替代普通 TLS;未认证连接回落到 dest
  #   enable: true
  #   users:
  #     - username: jls-user
  #       password: jls-password
  #   dest: www.example.com:443
  #   # sni: www.example.com # 留空时从 dest 推导
  #   # alpn: [h2, http/1.1]
  #   # proxy: ""
  #   # rate-limit: 0 # fallback 转发限速,单位 bit/s;0 表示不限速

JLS camouflage 实现原理 https://github.com/JimmyHuang454/JLS/blob/master/pdf/thuthesis-example.pdf

第3个版本跟 TLS 1.3 完全一模一样,除了 random 字段是特殊生成的。
2.1 基本原理

因为 TLS1.3 会生成 KeyShare 来保证此次对话是唯一的。因为 random 生成时加入了 KeyShare,所以攻击者是无法伪装成 Client 或 Server。

2.2 random 生成算法

生成一个随机数 N(16 字节),通过用户输入的 userIV 和 userPWD,使用 AES_256_GCM 对 N 加密。加密时,先把 ClientHello 和 ServerHello 中的 random 字段的 32 字节全部置换为 0,得出 Hello。

实际使用的:

  • 原文 plainText=N
  • 随机数 iv=sha256(utf8.encode(userIV) + Hello)
  • 密码 pwd=sha256(utf8.encode(userPWD) + Hello)
  • 附加消息 additionalText=null

加密后生成出默认长度为 16 字节的消息认证码 MAC 和 16 字节的密文 cipherText,通过拼接 cipherText + MAC 得出 32 字节的 FakeRandom 后填充进 Hello。

因为 random 也带有验证的功能[1],所以生成的 FakeRandom 的后 8 字节不能是:

  • 44, 4F, 57, 4E, 47, 52, 44, 01
  • 44, 4F, 57, 4E, 47, 52, 44, 00
  • 07, 9E, 09, E2, C8, A8, 33, 9C

如果是,则必须更新 N,重新生成一个 FakeRandom。

2.3 PSK 处理

如果 Client Hello 包含 Pre_Shared_Key 拓展,生成 FakeRandom 时,Pre_Shared_Key 应该包含真实的 Identity 参数,但 Binder 参数应该全置为 0(长度应与真实长度一致);生成完 FakeRandom 并填充进 Client Hello 后,再计算并填入真实 Binder,因为 Binder 会验证实际使用的 Client Hello。
2.4 Server 验证

Server 根据收到 Client Hello 的 random 来判断是否有效 Client,如果不是有效 Client,直接转发到伪装站。如果是有效 Client,则不需转发到伪装站,使用自签证书,完整按照 TLS 的流程处理。Server 发送的证书可以是任意内容,Client 无需验证该证书是否有效。

2.5 Client 验证

Client 根据收到的 Server Hello 中的 random 来判断是否有效 Server,如果无法验证 random,则认为是无效 Server。如果是有效 Server,则不需要验证证书是否有效(直接信任),按照正常 TLS 流程处理即可。

在全部阶段,都不应该出现"HelloRetryRequest"类型,如果出现则认为是无效 Server。

如果是无效 Server,也应正常按照 TLS 流程处理;如果能验证证书的有效性(非直接信任),建议 TLS 握手后表现成一个正常的 HTTP 请求。

2.6 建议

  • 如果开启了 0-RTT 功能,那么可能遭遇重放攻击
  • 如果选取支持 0-RTT 的伪装网站,相应的,你应该开启 0-RTT 功能来避免特征,而且如果伪装网站支持 Session 共享(即不同机器不同 IP 也接受 PSK),那么可能会暴露特征
  • 最好每三个月更换一次密码,密码和随机数长度应该大于 64 字节
  • 无法同时一起与 ECH[2] 使用

个人点评:

看上去是来平替 reality 的给协议搭配提供了更多选择

协议(vless/ss/anytls/…) + 传输层(xhttp/ws… ) + 安全层 tls/ reality /jls + 伪装( xdns/mc …)
有时间测试