В разборе VLESS я описал Reality в двух абзацах: подставляет чужой сертификат, наблюдатель видит обычный сайт, всё работает. Для обзора достаточно. Для понимания — нет, и я это понял по письмам после той статьи.
Главный вопрос там остался без ответа. Ладно, сертификат чужой. Но откуда сервер его берёт, что происходит, когда по вашему адресу стучится не клиент, а проверяющий, и почему нельзя взять любой популярный домен, вписать его в конфиг и жить счастливо?
Разберу механику подробно: будет технически, местами занудно, с матчастью про TLS. Инструкций по развёртыванию не будет. И признание на входе: часть этой механики я понял не с первого раза, а с третьего, причём момент с key_share дошёл до меня, только когда я читал чужой конфиг и вдруг сообразил, зачем там нужен огрызок из восьми символов. Так что если покажется, что я разжёвываю очевидное, — это я себе.
Почему обычный VPN по TLS всё равно отличается от браузера
Логика «завернём туннель в HTTPS, и его не отличат от сайта» выглядит железно: порт 443, шифрование, сертификат. На этой идее построены десятки решений, и все они по очереди перестали работать.
Причина в том, что TLS — это не только шифрование, но ещё и подробный разговор двух сторон перед тем, как шифрование начнётся. И разговор этот виден целиком. Первое сообщение называется ClientHello и идёт открытым текстом, а внутри на удивление много: какие версии протокола клиент поддерживает, какой список шифронаборов предлагает и, что важнее, в каком порядке, какие кривые умеет, какие расширения включены и в каком порядке идут. Плюс SNI — имя домена, к которому клиент направляется. И вот тут начинается интересное, потому что разные библиотеки составляют этот пакет по-разному. Chrome предлагает один набор шифров в одном порядке, Firefox другой, Safari третий. Стандартная библиотека Go, на которой написана половина сетевого софта, — четвёртый, и он не похож ни на один браузер ни капли.
Это и есть TLS-фингерпринт: не одно поле, а совокупность, слепок того, как клиент составил своё первое сообщение. Сравнивать такие слепки научились давно, у методов есть устоявшиеся имена вроде JA3 и JA4.
Аналогия банальная, но точнее я не придумал: почерк. Текст один, буквы те же, а рука разная.
[Изображение: разбор пакета ClientHello по полям — версия, шифронаборы, расширения, SNI — с подсветкой тех, что формируют фингерпринт]
Вот на этом старые решения и сыпались. Соединение идёт на 443, выглядит как HTTPS, а фингерпринт не совпадает ни с одним браузером на рынке — людей, которые ходят на сайты через самописный клиент на Go, примерно ноль. Значит, не браузер. Значит, туннель. Добавьте второй слой признаков: TLS внутри TLS, где браузер уже зашифровал запрос, а туннель шифрует его ещё раз, и у такой матрёшки характерные размеры пакетов и тайминги. Этим занимается XTLS-Vision. Но фингерпринт рукопожатия им не закрывается, держите это в голове.
TLS-фингерпринт и активное зондирование: две разные проверки
Важно развести два механизма, которые постоянно валят в кучу, — я сам их путал полгода, пока не нарисовал на бумажке.
Пассивный анализ. Система стоит на пути трафика и смотрит: сравнивает фингерпринт с профилями браузеров, оценивает размеры пакетов, ритм обмена, длительность сессии. Ничего не делает — наблюдает и копит подозрения. Молча.
Активное зондирование. Инструмент принципиально другой: заподозрив соединение, система сама идёт по тому же адресу и порту, изображает клиента, отправляет своё рукопожатие, иногда повторяет ваше — и смотрит, что ответит сервер. Это как тайный покупатель: вывеску можно повесить любую, но придёт человек, попросит товар, и станет понятно, магазин это или картонный фасад. Классическая связка «домен плюс сертификат» на этой проверке и ломается. Проверяющий приходит по адресу вашего сервера, а там либо тишина по HTTP, либо пустая заглушка, либо — самое смешное, я такое видел дважды — страница панели управления. Настоящих сайтов без содержимого не бывает. Обходить пытались по-разному: заглушка рядом, fallback на локальный nginx, и помогает это, скажем так, частично. Однодневка с тремя страницами лорем ипсума и нулевой посещаемостью — такой же демаскирующий признак, просто менее явный.
Идея Reality: не изображать сайт, а пользоваться настоящим
Ход мысли авторов, насколько я его понимаю, был такой: если подделка всегда хуже оригинала — давайте не подделывать. Впрочем, давайте по шагам.
Шаг первый. Клиент формирует ClientHello не своим почерком, а точной копией почерка настоящего браузера: за это отвечает библиотека uTLS, воспроизводящая профили Chrome, Firefox и Safari вплоть до порядка расширений и GREASE-значений. В конфиге это параметр fp. Фингерпринт получается не похожий на браузерный, а буквально браузерный — различие, которое я недооценивал.
Второй. В поле SNI клиент пишет не адрес вашего сервера, а домен стороннего сайта-прикрытия, и для наблюдателя соединение выглядит как обращение к этому сайту.
Третий — самый красивый, и именно он до меня долго не доходил. В ClientHello есть расширение key_share, где клиент передаёт открытый ключ X25519. Reality использует его как контейнер: внутрь кладётся метка, вычисленная из открытого ключа сервера (тот самый pbk в конфиге) и короткого идентификатора sid. Снаружи это просто случайные байты, каких в любом рукопожатии полно. Никаких лишних полей и пакетов не появляется — и когда я это осознал, стало обидно за потраченные вечера.
И наконец, четвёртый. Сервер проверяет метку своим закрытым ключом. Дальше развилка, и она решает вообще всё.
[Изображение: схема рукопожатия Reality — две ветки развилки: свой клиент и зонд, с указанием, что происходит в каждом случае]
Если метка верна — это свой. Сервер идёт к сайту-прикрытию, забирает настоящую цепочку сертификатов и отдаёт клиенту, но подпись в CertificateVerify подменяет своим ключом. Клиент, у которого в конфиге лежит pbk, эту подпись проверяет: совпало — на том конце действительно наш сервер; не совпало — клиент рвёт соединение и ведёт себя как браузер, которому не понравился сертификат.
Если метки нет или она неверна — а это ровно то, что произойдёт при зондировании или при случайном заходе браузером, — сервер прозрачно проксирует соединение на сайт-прикрытие, целиком, вместе с рукопожатием. Проверяющий получает настоящий сайт с валидным сертификатом, потому что это и есть настоящий сайт. Он просто съездил туда через ваш сервер, не зная об этом.
Отсюда, кстати, и устойчивость. Проверять нечего: по адресу действительно живёт то, что там должно быть. Аналогия, которая мне кажется рабочей, — магазин с честной витриной и настоящим товаром: зашёл прохожий или проверяющий — он в магазине, ему пробьют чек. А для своих есть служебная дверь, которая открывается только на определённый стук, и стоит она прямо в общем зале, от стены не отличить. Аналогия хромает, второго помещения физически нет. Но развилку передаёт.
Как выбирается сайт-прикрытие и почему от этого зависит всё
Самая недооценённая часть, про которую в гайдах пишут строчкой: «укажите любой популярный домен». Совет плохой, а требований, если честно, изрядно.
Технические. Сайт должен поддерживать TLS 1.3 — без него схема не работает — и уметь X25519. Желательно HTTP/2. И не должен требовать клиентских сертификатов.
География. Домен должен сочетаться с адресом вашего сервера: сервер в Нидерландах и прикрытие, которое обслуживается где-нибудь в Австралии, — картина странная, имя ведёт в одну сторону, адрес в другую.
Популярность. Сайт должен быть таким, куда люди реально ходят: соединение к домену, о котором в вашей стране не слышал никто, само по себе аномалия — тем более если таких соединений с одного адреса идёт много и подолгу.
Незаблокированность. Очевидно, но забывают. Попадёт домен-прикрытие в блокировку — туннель ляжет вместе с ним, хотя с сервером всё в порядке.
Стабильность. Ресурс не должен переезжать между хостерами.
И отдельный пункт, про который почти не пишут, а меня он в своё время удивил больше всего. Не берите домен из первого попавшегося гайда на GitHub: его оттуда взяли ещё несколько тысяч человек, и одно имя всплывает в SNI у сотен серверов — статистическая аномалия, которую видно без анализа содержимого. По-хорошему прикрытие подбирается под локацию и периодически пересматривается: это часть эксплуатации, а не разовая настройка. Для одного сервера вручную терпимо. Для инфраструктуры — рутина, которую держит мониторинг.
Что в итоге видит DPI
Картина со стороны наблюдателя выходит скучная — вернее, никакая, и в этом вся суть. Он видит соединение на порт 443 к непримечательному адресу, ClientHello с фингерпринтом браузера, SNI известного домена и зашифрованный поток. Он не видит признаков туннеля в рукопожатии, не видит сигнатуры TLS-в-TLS, за неё отвечает Vision, не видит лишних полей и «шума». А решит проверить активно — получит работающий сайт.
| Протокол | Что видно системе анализа | Результат проверки зондом |
|---|---|---|
| OpenVPN | Характерный заголовок, опознаётся уверенно | Отвечает не как веб-сервер |
| WireGuard | UDP с узнаваемой структурой первых пакетов | Молчит или отвечает нехарактерно |
| Shadowsocks | Поток без структуры, подозрителен самой бесформенностью | Молчит на любой запрос |
| VMess/VLESS поверх обычного TLS | Фингерпринт не совпадает с браузерным | Пустая заглушка или панель |
| VLESS + Reality | Браузерный фингерпринт, SNI живого домена | Настоящий работающий сайт |
[Изображение: сравнительная схема «что видит DPI» для OpenVPN, WireGuard, Shadowsocks и Reality]
Reality против обфускации и Shadowsocks
Разница тут, кстати, концептуальная, а все три подхода вечно валят в одну кучу. Shadowsocks в базовом виде шёл по пути «сделать трафик бесформенным»: никаких заголовков, никакой структуры, просто поток байтов. Идея работала ровно до тех пор, пока анализаторы искали известные сигнатуры, а потом научились смотреть на энтропию — и выяснилось: поток без структуры в интернете сам по себе редкость. Отсутствие признаков стало признаком. Мне эта мысль показалась почти издевательской, но она верная.
Обфускация — следующая попытка: добавим шума, набросаем сверху что-то похожее на легитимный протокол. Работает лучше, но упирается в ту же стену: маскировку писал человек, представлявший себе легитимный трафик, а представление всегда приблизительное. Где-то поле не то, где-то порядок, где-то тайминги.
Reality ничего не изображает и не добавляет: рукопожатие настоящее, фингерпринт браузерный, сертификат чужой настоящий, сайт за ним настоящий. Разница между «очень похоже» и «то же самое» качественная, и если унесёте из статьи одну мысль, пусть это будет она.
Где Reality может не сработать
Ладно, теперь честная часть. Идеальных решений не бывает, и вечную защиту я вам продавать не собираюсь: за десять лет я не встречал ни одной.
Белые списки с привязкой к адресам. Фильтрацию по именам доменов Reality проходит отлично: SNI разрешённый, пропускаем. Но если система сверяет ещё и то, ведёт ли имя на официальные адреса владельца, схема разваливается: ваш сервер стоит не в подсетях того сайта, чьё имя в SNI. Насколько массово такая сверка применяется — вопрос открытый, и утверждать я не берусь.
Статистика поведения. Рукопожатие безупречно, а вот что происходит после — уже нет. Соединение к новостному сайту, которое живёт шесть часов и перекачивает десятки гигабайт, выглядит странно независимо от того, как начиналось.
Блокировка по адресам и подсетям. Самое грубое и самое действенное. Выкосили диапазон хостера целиком — качество маскировки не значит ничего, до сервера просто нет маршрута. Спасает запас адресов в разных автономных системах, а это вопрос уже не протокола, а инфраструктуры.
Устаревшие профили. Браузеры обновляются, рукопожатия меняются, и клиент, изображающий Chrome полуторагодовой давности, выделяется не тем, что не похож на браузер, а тем, что похож на музейный экспонат.
Неудачное прикрытие. Всё, что написано выше про выбор домена. Плохой сводит на нет всю конструкцию.
Будет ли Reality работать через год? Не знаю. Осенью 2026-го работает, и лучше остального. Но методы анализа развиваются, и когда-нибудь появится следующая итерация — так было со всеми решениями до него.
Как убедиться, что у вас действительно Reality
Три уровня проверки, от ленивого к полезному.
Смотрим конфиг. Откройте профиль в своём клиенте. В строке подключения должно быть security=reality, рядом pbk (открытый ключ сервера), sid, fp (профиль фингерпринта, обычно chrome) и sni с доменом прикрытия. Плюс flow=xtls-rprx-vision — это про Vision, но в связке они идут почти всегда. Если вместо reality стоит tls, а в конфиге ваш собственный домен, у вас классическая схема: рабочая, но живёт хуже.
Проверяем соединение. Подключились и прогнали проверку: адрес сменился, DNS не утекает, WebRTC не показывает реальный адрес. Последние два пункта к Reality отношения не имеют, но обнуляют весь смысл, если не в порядке.
[Изображение: страница проверки соединения с подсвеченными полями — IP, DNS, WebRTC]
Проверяем устойчивость на практике. Единственная проверка, которая по-настоящему имеет значение, и синтетические тесты её не заменят. Посидите несколько дней в разных условиях: дома, на мобильном, в чужом Wi-Fi. Обязательно в вечерний час пик. Посмотрите, что происходит при переключении между сетями и после того, как телефон часок полежал в кармане. Вот тут и вылезает разница между «в лаборатории работает» и «работает у меня» — по моему опыту, на третий-четвёртый день, а не в первые десять минут. Проверять всё это надо до того, как заплатили: обход блокировок у каждого оператора в России выглядит немного по-своему.
Если сводить к одному абзацу
Reality решает не задачу шифрования — её давно решил TLS. Он решает задачу неотличимости: чтобы и пассивный анализ, и активная проверка видели обычное посещение обычного сайта. Не похожее на него, а именно его — с настоящим сертификатом, фингерпринтом и ответом на том конце. Всё остальное — детали.
Проверять такие вещи стоит руками. HubHide работает на VLESS и Reality, тест 14 дней бесплатно и без карты — смотрите на своём операторе, в своё вечернее время, на своих устройствах. Не подойдёт — ничего не потеряли. А заодно загляните в конфиг: теперь вы знаете, что там должно быть.
Частые вопросы
Что такое Reality в VPN?
Это режим работы TLS в Xray, при котором сервер не использует свой домен и сертификат, а подставляет настоящую цепочку сертификатов стороннего популярного сайта. Своим клиентам он отдаёт туннель, остальным прозрачно проксирует запрос на этот самый сайт. Обычно применяется в связке с VLESS и XTLS-Vision.
Чем Reality отличается от обфускации?
Обфускация добавляет к трафику маскирующий слой — шум или имитацию другого протокола, и качество её ограничено тем, насколько точно автор представлял легитимный трафик. Reality ничего не добавляет и не имитирует: рукопожатие настоящее, фингерпринт браузерный, сертификат реального сайта. Это разница между похожей копией и оригиналом.
Можно ли обнаружить Reality?
Само рукопожатие надёжно не отличается от браузерного, и зондирование его не вскрывает. Уязвимые места в другой плоскости: статистика поведения соединения, несоответствие домена в SNI и адресов владельца при строгих проверках, плюс блокировка подсетей хостера, против которой маскировка бессильна.
Почему Reality работает при белых списках?
Когда фильтрация пропускает только разрешённые домены и опирается на SNI, Reality проходит: в SNI стоит имя легитимного разрешённого сайта. Если же система дополнительно сверяет, ведёт ли имя на адреса настоящего владельца, схема перестаёт работать. Универсальной гарантии здесь нет, и любой, кто её даёт, лукавит.