Xray-core icon indicating copy to clipboard operation
Xray-core copied to clipboard

Long-Term Enhancement: Dynamic, Fingerprint-Aware Caching for Post-Handshake Mimicry

Open DavidOsipov opened this issue 6 months ago • 3 comments

English

This is a follow-up proposal to the discussion in issue #4778, intended to formalize the long-term solution suggested by @RPRX for the project's backlog.

The Motivation

The fix in #4778 effectively solves the static NewSessionTicket detection vector. However, the discussion revealed a more nuanced challenge: the current implementation probes the target using a single, static client fingerprint (e.g., uTLS for Chrome 131).

Observations showed that server behavior is not uniform. For example:

  • www.bilibili.com sends a different number and length of post-handshake packets in response to a ClientHello from Chrome vs. one from Go.
  • Other servers, like wechat.com, appear to have a consistent response regardless of the client fingerprint.

This variance means a mismatch can still occur if the user's client fingerprint differs from the one used by the REALITY server for probing, creating a potential vector for advanced traffic analysis.

Proposed Mechanism: Dynamic "Live Learning"

A more resilient long-term solution is to implement the "live learning" mechanism RPRX outlined. This would make REALITY's mimicry adaptive to the specific client connecting.

The proposed server-side logic:

  1. Fingerprint Inspection: On a new connection, the REALITY server inspects the incoming ClientHello fingerprint.
  2. Cache Lookup: It checks a local cache for a stored post-handshake pattern corresponding to the {target_server, client_fingerprint} tuple.
  3. Live Probe & Cache Miss: If the pattern is not cached, the server forwards the client's initial handshake directly to the real target. It passively "sniffs" the subsequent post-handshake exchange (specifically the number and lengths of NewSessionTicket records) and stores this new pattern in its cache.
  4. Cache Hit & Mimicry: On all future connections using the same {target_server, client_fingerprint} tuple, REALITY serves the response by sending padding packets that perfectly match the lengths and count from the cached pattern.

Implementation Considerations

  • One-Time Latency Cost: This introduces a one-time probing delay (estimated ~30s) for each new fingerprint-target pair. This is a reasonable trade-off for the increased stealth.
  • Concurrency and Caching: The caching mechanism must be thread-safe and handle locking correctly to prevent race conditions when multiple clients with a new fingerprint connect simultaneously. The fixes for the locking behavior in the initial implementation are a good reference.
  • Client-Side Hook: This feature might leverage or depend on the client's "SpiderX mechanism" to gracefully handle the initial pass-through connection, which could have implications for non-Xray-core clients.

A quick note: I am not an expert in this domain and have used an LLM to help me structure and translate this proposal based on the developer discussion. The goal is simply to formalize this valuable idea from the previous thread so it can be tracked. My apologies for any technical inaccuracies. Thank you for your amazing work.



Русский

Это issue является продолжением дискуссии из #4778 и предназначено для формализации долгосрочного решения, предложенного @RPRX, для бэклога проекта.

Мотивация

Патч в #4778 эффективно решает проблему обнаружения через статический NewSessionTicket. Однако в ходе обсуждения выявилась более тонкая проблема: текущая реализация зондирует целевой сервер, используя единственный статический отпечаток клиента (например, uTLS для Chrome 131).

Наблюдения показали, что поведение серверов неоднородно. Например:

  • www.bilibili.com отправляет разное количество и длину post-handshake пакетов в ответ на ClientHello от Chrome и от Go.
  • Другие серверы, как wechat.com, похоже, отвечают одинаково, независимо от отпечатка клиента.

Эта разница означает, что если отпечаток клиента пользователя отличается от того, который сервер REALITY использовал для зондирования, может возникнуть несоответствие. Это создает потенциальный вектор для продвинутого анализа трафика.

Предлагаемый механизм: Динамическое «обучение в реальном времени»

Более устойчивое долгосрочное решение — внедрить механизм «живого обучения», который был предложен RPRX. Это позволит имитации REALITY адаптироваться под конкретного подключающегося клиента.

Предлагаемая логика на стороне сервера:

  1. Анализ отпечатка: При новом соединении сервер REALITY анализирует отпечаток входящего ClientHello.
  2. Проверка кэша: Сервер ищет в локальном кэше сохранённый паттерн post-handshake сообщений, соответствующий паре {целевой_сервер, отпечаток_клиента}.
  3. «Живое» зондирование (промах кэша): Если паттерн не найден, сервер перенаправляет начальное рукопожатие клиента напрямую к реальной цели. Он пассивно «прослушивает» последующий обмен post-handshake сообщениями (в частности, количество и длину записей NewSessionTicket) и сохраняет этот новый паттерн в кэш.
  4. Попадание в кэш и имитация: При всех последующих соединениях, использующих ту же пару {целевой_сервер, отпечаток_клиента}, REALITY формирует ответ, отправляя пакеты-заполнители, которые идеально соответствуют количеству и длинам из кэшированного паттерна.

Аспекты реализации

  • Однократная задержка: Этот подход вносит однократную задержку на зондирование (около 30с) для каждой новой пары «отпечаток-цель». Это разумный компромисс для повышения скрытности.
  • Параллелизм и кэширование: Механизм кэширования должен быть потокобезопасным и корректно использовать блокировки для предотвращения состояний гонки при одновременном подключении нескольких клиентов с новым отпечатком. Исправления блокировок в первоначальной реализации служат хорошим примером.
  • Клиентская часть: Эта функция может использовать или зависеть от «механизма SpiderX» на стороне клиента для корректной обработки первоначального «сквозного» соединения, что может иметь значение для клиентов, не основанных на Xray-core.

Небольшое примечание: Я не являюсь экспертом в этой области и использовал LLM, чтобы помочь мне структурировать и перевести это предложение на основе обсуждения разработчиков. Цель состоит в том, чтобы просто формализовать эту ценную идею из предыдущей ветки для дальнейшего отслеживания. Приношу извинения за возможные технические неточности. Спасибо за вашу потрясающую работу.



中文

此 issue 旨在跟进 #4778 中的讨论,并将其开发者 @RPRX 提出的长远解决方案正式化,以便项目将其纳入待办事项。

背景动机

在 #4778 中的修复有效地解决了静态的 NewSessionTicket 检测向量。然而,讨论也揭示了一个更细微的挑战:当前的实现方案使用一个固定的客户端指纹(例如 uTLS 的 Chrome 131 指纹)来探测目标服务器。

但观察表明,不同服务器的行为并非完全一致。例如:

  • 对于来自 Chrome 和来自 Go 的不同 ClientHello 指纹,www.bilibili.com 服务器返回的握手后数据包在数量和长度上都有差异。
  • 而其他一些服务器(如 wechat.com)则似乎无论客户端指纹如何,其响应都保持一致。

这种行为上的差异意味着,如果用户实际使用的客户端指纹与 REALITY 服务器探测时所用的指纹不同,模仿出的流量就可能存在细微偏差,这可能成为高级流量分析的一个潜在特征。

提议的机制:动态“实时学习”

一个更具韧性的长远解决方案,是实现 RPRX 所构思的“实时学习”机制。这将使 REALITY 的模仿行为能够自适应于每个连接的客户端。

提议的服务器端逻辑如下:

  1. 指纹识别: 当一个新连接建立时,REALITY 服务器首先识别其 ClientHello 的指纹。
  2. 查询缓存: 服务器在本地缓存中查找是否存在与 {目标服务器, 客户端指纹} 这个元组相对应的握手后行为模式。
  3. 实时探测(缓存未命中): 如果缓存中没有记录,服务器会将该客户端的首次握手过程直接转发给真实的目标服务器。在此期间,它被动地“嗅探”随后的握手后通信(特别是 NewSessionTicket 记录的数量和长度),并将这个新模式存入缓存。
  4. 缓存命中与模仿: 对于后续所有使用相同 {目标服务器, 客户端指纹} 元组的连接,REALITY 将根据缓存中的模式,发送数量和长度完全匹配的填充数据包来进行模仿。

实现时需考虑的要点

  • 一次性延迟成本: 对于每一个新的“指纹-目标”组合,此机制会引入一次性的探测延迟(估计约 30 秒)。为了换取更高的隐蔽性,这是一个合理的代价。
  • 并发与缓存: 缓存机制必须是线程安全的,并正确处理锁,以防止多个持有新指纹的客户端同时连接时可能引发的竞争条件。初期修复中对锁行为的改进是很好的参考。
  • 客户端联动: 此功能的实现可能需要利用或依赖于客户端的“SpiderX 机制”,以优雅地处理首次“穿透”连接,这对于非 Xray-core 客户端或许有一定影响。

附言: 我并非此领域的专家,此提案是基于对开发者讨论的理解,并借助 LLM 辅助整理和翻译而成。其目的仅仅是将上一议题中这个宝贵的想法正式化,以便追踪。如果其中存在任何技术上的不准确之处,我先行致歉。感谢你们在这个项目上所做的卓越工作。

DavidOsipov avatar Jun 07 '25 11:06 DavidOsipov

看了下相当于详细解释了 https://github.com/XTLS/Xray-core/issues/4778#issuecomment-2952152366

另外我也挺关心最新版 Chrome 137 触发的第三个小包长度增加了 9 是什么原因,因为有可能是 uTLS 只模仿了 Client Hello 但后面少发了什么的问题,且 CH 后消息长度可能不符合 Chrome,需要一个类似 Aparecium 的项目给 uTLS 找找茬 @ban6cat6

RPRX avatar Jun 07 '25 12:06 RPRX

还有既然已经引入了探测机制,那么 REALITY README 写的“预先构建模式”,即提前采集目标网站特征、不用每次都 call target,以及这个也可以提上日程了:https://github.com/XTLS/REALITY/blob/90e738a94c8ca934d61932afe471712197a3dd36/tls.go#L321

RPRX avatar Jun 07 '25 12:06 RPRX

https://github.com/XTLS/Xray-core/issues/4778#issuecomment-2952490470

RPRX avatar Jun 07 '25 13:06 RPRX

https://github.com/XTLS/Xray-core/issues/4778#issuecomment-2996196290

RPRX avatar Jun 23 '25 11:06 RPRX

English

Hi @Fangliding,

Just a quick note on the closing of this issue.

Since this issue (#4788) was created to track the long-term solution for fingerprint-aware caching, and the implementation is still under active discussion and development (based on the excellent progress in threads like #4778 and the work in XTLS/REALITY), it might be beneficial to keep it open for now.

According to typical open-source project workflows, feature-request issues like this are usually kept open until the corresponding code has been merged into the main branch. This helps the community track the progress of the feature and serves as the official backlog item that developer @RPRX pointed to.

Would you mind reopening it? Thanks for all your contributions and hard work on this!


中文 (Chinese)

Hi @Fangliding,

你好,关于这个 issue 被关闭的事情,想和你沟通一下。

这个 issue (#4788) 是用来追踪“感知客户端指纹的动态缓存”这个长远解决方案的,目前相关的开发和讨论(例如在 #4778 中的精彩进展以及 XTLS/REALITY 仓库中的工作)似乎还在活跃进行中。

按照通常的开源项目协作流程,类似的功能请求 issue 一般会保持开放状态,直到相关代码被正式合并到主分支。这样做可以方便社区成员清晰地追踪重要功能的开发进度,也能作为 @RPRX 之前所说的官方待办事项。

请问可以考虑重新打开(Reopen)这个 issue 吗?非常感谢你为此付出的努力!

DavidOsipov avatar Jul 10 '25 17:07 DavidOsipov

还在开发吗 我看reality库0个PR上次提交还是两个星期前以为已经完成了

Fangliding avatar Jul 10 '25 17:07 Fangliding

English

Ah, that makes perfect sense why you thought development had stopped.

There's a bit of a funny situation here: the developers are having a very active, ongoing discussion, but for some reason, they are doing it in the original closed issue, #4778.

All the real-time brainstorming, code snippet sharing (like the draft work from yuhan6665), and key discoveries are happening in that thread.

So you are absolutely right that there haven't been any new PRs in the XTLS/REALITY repo itself. It seems the work is still in the deep R&D phase before a final PR is made.

Given this, the feature is definitely still under active development. Would you mind reopening this issue (#4788) so it can serve as the official tracker for all that work?

Thanks again!


中文 (Chinese)

啊,原来是这样,我明白你为什么会认为开发已经完成了。

这里有个很有趣的情况:开发者们确实在非常活跃地持续讨论,但他们不知为何选择在那个已经关闭的 issue #4778 里进行。

所有实时的头脑风暴、代码片段分享(比如 yuhan6665 的草稿)和重要的发现都在那个帖子里发生。

所以你看到的“XTLS/REALITY 仓库最近没有新 PR”是完全正确的。看起来这项工作还处在最终 PR 提交前的深度研发阶段。

因此,这个功能确实仍在积极开发中。可以麻烦你重新打开这个 issue (#4788),让它继续作为这项工作的官方追踪项吗?

再次感谢!

DavidOsipov avatar Jul 12 '25 06:07 DavidOsipov

https://github.com/XTLS/Xray-core/issues/4778#issuecomment-3072047745

RPRX avatar Jul 15 '25 06:07 RPRX

https://github.com/XTLS/Xray-core/issues/4778#issuecomment-3091241760

RPRX avatar Jul 19 '25 00:07 RPRX