Как SHIFROM ведёт соединение с ретранслятором внутри VLESS+REALITY
Содержание
SHIFROM — мессенджер с открытым кодом и сквозным шифрованием, спроектированный исходя из того, что сеть между устройством и ретранслятором враждебна. Первым выходит приложение для Android, версии для iOS и веба в планах. Один из маршрутов, по которым клиент может дойти до ретранслятора, — VLESS+REALITY, внешний протокол из проекта Xray-core, встроенный прямо в приложение. Эта заметка о том, как устроен этот маршрут, где он стоит, что показал наш единственный полевой прогон и чего он не защищает.
Область, заранее. SHIFROM находится в стадии Alpha 2, поддерживаемого публичного релиза пока нет (APK Alpha 1 на GitHub — историческая тестовая сборка). Наша собственная протокольная композиция (X3DH, Double Ratchet и Sealed Sender поверх примитивов libsodium) не проходила независимый аудит. Всё, что ниже сказано о поведении REALITY в реальной сети, опирается на одну сессию, проведённую основателем: один бюджетный Android-телефон, один мобильный оператор (МТС, мобильные данные, без VPN) в одном российском регионе, 7 мая 2026 года. Это говорит о том, что произошло в той сессии, а не о том, что REALITY проходит любую DPI-политику, любого оператора или даже того же оператора сегодня. Там, где заметка описывает устройство, она опирается на наши архитектурные решения (ADR-019, ADR-020) и код, который они описывают, а не на измерения. О том, где и как развёрнута точка входа REALITY, заметка намеренно не говорит ничего.
Что такое REALITY
REALITY делает проксированное соединение похожим для наблюдателя на пути на обычную сессию TLS 1.3 с известным сайтом, которым мы не управляем, — сайтом-маскировкой. Рукопожатие клиента называет этот сайт. Клиент, у которого есть заранее согласованные параметры точки входа, аутентифицируется внутри рукопожатия с помощью согласования ключей X25519 и стандартного шифрования записей TLS 1.3 и получает туннель. Любое соединение, не прошедшее эту проверку, включая активное зондирование, побайтно пересылается на настоящий сайт-маскировку, так что зондирующий получает подлинную цепочку сертификатов этого сайта. Стоит назвать и побочный эффект: сайт-маскировка видит только соединения, не прошедшие аутентификацию, и приходят они с адреса точки входа. Клиенты SHIFROM аутентифицируются и до него не доходят.
Не менее важно, чего REALITY не делает. Он не скрывает сам факт соединения, его длительность и объём переданных байт. Это не система анонимности. Он работает против фильтрации, которая опирается на внешний вид TLS-потока, и может не пройти любую DPI-политику. Исследования по обнаружению REALITY существуют; наша исследовательская заметка от мая 2026 года фиксировала преобладающее мнение практиков, что масштабируемой атаки в продакшене известно не было, и считала, что это может измениться.
Почему мессенджеру нужен не один маршрут
Сопутствующая заметка «Когда TLS остаётся открытым, а принятые к отправке данные не доходят» показывает, как прямой WebSocket-путь может отказать в мобильной сети без единой ошибки. ADR-019 фиксирует более раннюю, отдельную проблему: попытки дойти до ретранслятора через Tor с мостами, которые держит сам проект, зависали в сетях российских операторов, и документ связывает это с замедлением длинных TLS-потоков к адресам дата-центров. Этих прогонов нет в нашей публичной таблице полевых тестов, поэтому цифр из них мы здесь не приводим, а сопутствующая заметка объясняет, почему мы осторожны с любыми порогами.
ADR-019 фиксирует и ограничения, которые привели к REALITY. Маршрут должен работать без установки отдельного приложения, а значит, не подходят схемы, зависящие от отдельного VPN- или прокси-клиента. И он не должен опираться на протоколы, которые документ описывает как распознаваемые и блокируемые у российских операторов, например WireGuard и OpenVPN. REALITY не пытается выглядеть никак; он пытается выглядеть как что-то обычное.
Как и заключает сопутствующая заметка, ни один транспорт не является фундаментом. REALITY — один маршрут из нескольких, и наша исследовательская заметка говорит, что он никогда не должен стать единственным.
Где стоит REALITY: транспорты и режимы приватности
Клиент общается с ретранслятором через один транспортный интерфейс, за которым стоят несколько маршрутов:
- Direct WSS: маршрут с наименьшими накладными расходами для обычных сетей.
- WSS через встроенный Xray VLESS+REALITY: для сетей, где DPI мешает прямому WSS.
- WSS через onion-сервис Tor v3: на сегодня лучше всего скрывает сетевое происхождение, но рассчитан только на текст.
- REST send/poll: не отдельный внешний маршрут, а запасной способ доставки для сетей, которые пропускают HTTPS, но портят долгоживущие WebSocket-фреймы. Переход между WebSocket и REST не меняет криптографию сообщений.
Транспорт пользователь не выбирает. Он выбирает режим приватности, а менеджер транспорта проходит упорядоченную цепочку, которую этот режим разрешает:
| Режим | Цепочка | Если все варианты исчерпаны |
|---|---|---|
| Standard (по умолчанию) | Direct WSS → REALITY → Tor | видимая пользователю ошибка |
| Private | REALITY → Tor | видимая пользователю ошибка |
| Ghost | только Tor | отказ без понижения; никогда не переходит на менее приватный маршрут |
Private существует для тех, кто считает любое прямое соединение с известной точкой ретранслятора поверхностью для сопоставления. Ghost никогда не откатывается на REALITY или Direct WSS: если Tor не запускается, приложение показывает «Cannot reach relay», а не молча использует менее приватный маршрут. В ранних исследованиях рассматривалась обёртка Tor внутри REALITY для этого режима; в выпущенном Ghost её нет.
Когда активен маршрут REALITY, ретранслятор видит источником TCP-соединения точку входа REALITY, а не устройство пользователя. Точка входа видит адрес пользователя, и обе стороны держит один и тот же оператор. Поэтому ADR-019 отказался от дополнительного Tor-звена между точкой входа и ретранслятором на стороне сервера: оно добавило бы задержку и новые отказы, скрывая информацию от стороны, которая и так управляет обоими концами. Sealed Sender скрывает личность отправителя внутри конверта в любом режиме; режим меняет видимость на уровне IP, а не криптографию приложения.
Точка входа пересылает трафик только на ретранслятор и отбрасывает любые другие направления, поэтому не может служить прокси общего назначения. Журнал отдельных соединений у неё отключён; в её логах только сообщения о запуске и неустранимые ошибки.
Как Xray работает внутри Android-приложения
Клиент встраивает Xray-core через libXray — мобильную обёртку, которую поддерживает XTLS, — собранную gomobile в JNI-библиотеку и загружаемую в собственный процесс SHIFROM. Сборка идёт через CI в репозитории из неизменённого upstream-кода. Xray-core распространяется под MPL-2.0, SHIFROM — под AGPL-3.0-or-later; исходники Xray мы не меняем, и ADR-019 отмечает, что форк заново открыл бы вопрос совместимости лицензий.
Ядро работает внутри foreground-сервиса сообщений, который у приложения уже есть, и открывает SOCKS5-порт на локальном интерфейсе; клиент ретранслятора подключается через этот порт. ADR-019 называет две причины работать внутри процесса, а не отдельной программой. Агрессивные менеджеры памяти на бюджетных телефонах склонны убивать «осиротевший» дочерний процесс отдельно, а ядро внутри процесса останавливается и перезапускается вместе с приложением и не требует второго постоянного уведомления. Кроме того, отдельному исполняемому файлу понадобились бы дополнительные разрешения. Сервис проходит состояния Off, Starting, Ready и Failed — так же, как сервис Tor.
Прежде чем маршрут считается рабочим, менеджер запускает его, ждёт готовности SOCKS, а затем через этот порт проверяет health-эндпоинт ретранслятора — то есть доказывает путь целиком, а не только локальный порт. На подготовку REALITY даётся до 30 секунд, потому что холодная инициализация встроенного ядра на нашем тестовом телефоне занимала примерно столько (ADR-020); тёплый перезапуск укладывается в миллисекунды. У самой проверки свой бюджет для каждого маршрута: 25 секунд для прямого (две попытки по 10 секунд), 30 для REALITY и 90 для Tor. Рабочий маршрут приложение запоминает на 24 часа, только если это первый маршрут режима; когда побеждает запасной, память сбрасывается, и следующий проход снова начинается с первого маршрута, а не застревает на Tor. Цепочка проходится при холодном старте, перезапуске сервиса, смене режима и смене сети. После подключения деградацию WebSocket обрабатывает слой REST-фолбэка, а не повторный проход по цепочке.
Пользователь видит постоянное уведомление: «Connecting via …», затем «Online via …» с названием активного маршрута или «Cannot reach relay (tried N)» с кнопкой повтора, если не сработал ни один маршрут. Смена режима разрывает соединение и запускает проход по новой цепочке.
Это прокси внутри приложения, а не VPN для всего устройства. С VPN, который у пользователя уже включён, отношения конкурентные, а не дополняющие: по ADR-019, VPN забирает трафик приложения, и маршрут REALITY либо не работает, либо становится лишним, потому что наблюдатель в сети теперь видит VPN. Отдельная разведка по совместимости с VPN, начатая в июне 2026 года, охватывает прямой и REST-пути и не охватывает REALITY.
Что показал полевой прогон и чего не показал
В публичной таблице полевых тестов одна строка про REALITY. 7 мая 2026 года на бюджетном телефоне через мобильные данные МТС в одном российском регионе, без VPN и без отдельного прокси или Tor-приложения, внешний транспорт REALITY был доступен от начала до конца. Это был приёмочный прогон для ADR-019, с клиентом-двойником на эмуляторе. Результат: пройден. Задержка: не записана. Повторов: нет.
Это все публичные доказательства. ADR-019 изначально называл это «подтверждённым в продакшене»; позднейшая поправка исправила формулировку на то, чем это было: приёмочный прогон основателя на одном устройстве, у одного оператора, в один день. Таблица перечисляет, чего не хватает: одна модель телефона, один регион, версия Android не записана, независимого воспроизведения нет, а WebSocket-трафик в реальном времени внутри REALITY на пути Tele2 LTE из сопутствующей заметки спроектирован, но в поле не проверен. REALITY не проектировался против описанного там зависания, и эксперимента, который отделил бы, помогает ли он, мы не проводили.
План тестов режимов приватности описывает восемь сценариев, в нескольких участвует REALITY (например, режим Standard на российском телефоне без VPN: Direct WSS должен отказать, REALITY — сработать). Публичная таблица не содержит ни одного их прогона, поэтому мы из них ничего не утверждаем.
Чего это не делает
- Это не анонимность. Точка входа видит адрес пользователя, и ретранслятор держит тот же оператор.
- Ретранслятор по-прежнему видит время, размер сообщений, аутентифицированные сессии и адресатов доставки. Ни один из маршрутов здесь не устраняет анализ по времени и объёму, а противник, одновременно наблюдающий выход из сети и вход в ретранслятор, находится за пределами нашей модели угроз.
- Это не помогает против блокировки по адресу. Маскировка меняет то, как классифицируется поток, а не то, есть ли адрес в списке блокировок. Это верно для любого прокси, включая REALITY.
- Это зависит от сайта, которым мы не управляем. Если сайт-маскировка изменится или ограничит доступ так, что пересылка сломается, зондирование перестанет видеть настоящий сайт, и точку входа могут переклассифицировать.
- Это переносит TCP. Медиа в реальном времени по UDP были вне рамок этого этапа.
- Пока это есть только в Android-приложении. Версии SHIFROM для iOS и веба в планах; как этот маршрут будет устроен в них, ещё не решено.
- Это не затрагивает сквозное шифрование. Точка входа видит только зашифрованные конверты; её компрометация не раскрывает текст сообщений. Это верно ровно настолько, насколько верна не прошедшая аудит протокольная композиция.
Что дальше
Пробелы выше и задают работу: повторные прогоны REALITY, другие операторы и регионы, WebSocket-трафик в реальном времени внутри REALITY на пути Tele2 LTE — каждый как строка таблицы со своими условиями, включая неудачи. Сборка встроенного ядра под iOS ведётся отдельно. Наша исследовательская заметка рекомендует внешний разбор совместного распространения MPL-2.0 и AGPL до Beta. Ни у чего из этого нет даты.
SHIFROM — проект с открытым кодом (AGPL-3.0-or-later). Архитектурные решения, модель угроз, таблица полевых тестов и известные проблемы открыты публично. Если вы работаете над транспортами для враждебных сетей или хотите найти дыры в наших, код и проектная документация лежат на github.com/LiudvigVladislav/SHIFROM, а проект — на shifrom.com.