
Читая статьи про прокси, можно подумать, что VLESS с XHTTP — это чуть ли не единственный рабочий протокол проксирования в условиях блокировок. На самом деле существуют не менее современные альтернативы. Сегодня я расскажу о протоколе Naive, его особенностях, а также о настройке клиента и сервера с использованием sing-box и Caddy.
ClientHello и uTLS
Почти все популярные сейчас прокси-протоколы для стороннего наблюдателя маскируются под обычный HTTPS-трафик (как будто кто-то открывает сайт в браузере). Такие соединения зашифрованы, но первый пакет от клиента к серверу — исключение. Он называется ClientHello и содержит версию TLS, список поддерживаемых шифров, HTTP-протокол, домен запрашиваемого сайта и прочее. Эти данные передаются в открытом виде и отличаются от браузера к браузеру. Перехватив этот пакет, можно довольно точно определить программу, которая его отправила. Xray и sing-box написаны на Go, поэтому без дополнительных ухищрений их ClientHello соответствует стандартному для Go — такие соединения можно распознать и заблокировать. Для маскировки оба проекта используют библиотеку uTLS, которая позволяет сделать ClientHello похожим на ClientHello реального браузера (Chrome, Firefox или др.). Так уже лучше (замаскирован первый пакет), но всё равно остаются небраузерное поведение, своеобразные длины пакетов, другой ритм трафика.
О NaïveProxy
Автор Naive решил, что вместо точечной маскировки различных параметров проще взять сетевой стек реального браузера (Chromium), чтобы не только ClientHello, но и всё остальное было не просто похожим, а идентичным. Он взял исходные коды Chromium и удалил всё ненужное для этой задачи, оставив только 0.3% от оригинала. Мультиплексирование обеспечивается самим HTTP/2. Дополнительно добавлен свой padding с довольно простым алгоритмом (об этом ниже), чтобы затруднить анализ длин пакетов и выявление прокси.
Основной репозиторий: https://github.com/klzgrad/naiveproxy
Важно, что Naive-клиенты должны уметь работать с обычными HTTP/2-прокси, не знающими об особенностях Naive, и наоборот, Naive-серверы должны уметь работать с обычными HTTP/2-клиентами. Поэтому нужно различать совместимость с Naive-сервером и полноценную реализацию идеи Naive. В sing-box клиентский naive outbound использует сетевой стек Chromium/Cronet. Другие клиенты могут быть лишь совместимыми с Naive-сервером, но использовать обычный TLS/HTTP-стек вместо браузерного и поэтому не воспроизводить ту маскировку, ради которой изначально создавался Naive.
Padding
В протокол заложен довольно простой механизм padding, когда во фреймы добавляются лишние байты, чтобы динамически менять их длину и осложнять анализ. Используются три приёма:
В первые 8 DATA-фреймов потока в каждом направлении добавляется padding. К данным добавляется заголовок: 2 байта длины оригинальных данных, 1 байт длины padding, оригинальные данные, нули от padding.
В CONNECT-запросы и ответы добавляются заголовки со случайными данными произвольной длины, чтобы увеличить длину фреймов.
Дополнительные фреймы END_STREAM перед каждым RST_STREAM.
Перед написанием статьи я решил проверить сниффером все эти механизмы и обнаружил, что sing-box в первом типе padding вместо нулей отправляет произвольные данные, среди которых попадаются, например, имена доменов и заголовки от прежних запросов. После изучения исходного кода стало понятно, что sing-box добавляет байты в буфер, но не обнуляет их (как на клиенте, так и на сервере), а буферы при этом лежат в общем пуле и переиспользуются. Из-за этого через сервер потенциально могли утечь данные других клиентов. Сделал два PR с обнулением, которые были приняты (1, 2).

Настройка клиента sing-box
Нужна версия sing-box 1.13 или новее. Я не буду описывать всю конфигурацию, дам только пример outbound. Более подробно тема конфигурации и запуска оригинального клиента раскрыта в моей статье о sing-box.
{ "type": "naive", "tag": "Proxy1", "server": "1.2.3.4", "server_port": 443, "username": "username", "password": "password", "insecure_concurrency": 1, "udp_over_tcp": { "enabled": true }, "quic": false, "tls": { "enabled": true, "server_name": "s1.example.com" } }
tag— произвольное имя прокси в рамках конфигурации.server— IP вашего прокси.usernameиpassword— логин и пароль.insecure_concurrency— количество одновременных соединений. Автор настоятельно рекомендует ставить 1 (но точно не больше 4), потому что чем больше конечных соединений мультиплексируется в одном туннеле, тем сложнее анализировать длины пакетов внутри туннеля.udp_over_tcp— включаем поддержку UDP.server_name— имя вашего домена (или поддомена), с которым будет работать Caddy на сервере.
Настройка Caddy
Caddy получит бесплатный TLS-сертификат для вашего домена и будет принимать входящие подключения. При наличии заголовка Proxy-Authorization с правильными логином и паролем соединение будет передано в sing-box по протоколу HTTP/2 Cleartext, иначе клиенту будет отправлена страница сайта-заглушки (для защиты от активного сканирования).
Необходимо установить Caddy и отредактировать его конфигурацию. Это делается очень просто: буквально несколько команд и один текстовый файл.
Официальная инструкция по установке: https://caddyserver.com/docs/install
Редактируем файл /etc/caddy/Caddyfile:
{ email admin@example.com auto_https disable_redirects } :443, https://s1.example.com { tls { issuer acme { disable_http_challenge } } route { @naive { method CONNECT header Proxy-Authorization "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" } handle @naive { reverse_proxy h2c://127.0.0.1:1080 { header_up Proxy-Authorization {header.Proxy-Authorization} } } handle { root * /srv/naive-fallback file_server } } }
s1.example.com— домен из клиентской конфигурации sing-box.Строка после
Basicв заголовкеProxy-Authorization— это base64 от строкиusername:passwordиз клиентской конфигурации./srv/naive-fallback— путь к коду сайта-заглушки (можно ограничиться файломindex.html).
Перезапускаем Caddy (systemctl restart caddy) и проверяем, что в браузере открывается наш сайт-заглушка.
Настройка сервера sing-box
Опять же нужна версия sing-box 1.13 или новее.
Инструкция по установке: https://sing-box.sagernet.org/installation/package-manager/
Редактируем файл /etc/sing-box/config.json:
{ "log": { "level": "warn", "output": "/var/log/sing-box/sing-box.log" }, "inbounds": [ { "type": "naive", "tag": "naive-in", "network": "tcp", "listen": "127.0.0.1", "listen_port": 1080, "users": [ { "username": "username", "password": "password" } ] } ], "outbounds": [ { "type": "direct" } ] }
Не забудьте поменять username и password на те, которые используются в клиенте sing-box и Caddy.
Перезапускаем sing-box (systemctl restart sing-box). Всё готово!
Заключение
Я рассказал о протоколе Naive и показал один из вариантов настройки: клиент на sing-box, Caddy как TLS-терминатор и серверный inbound sing-box. Но существуют и другие варианты — например, через форк Caddy от автора Naive. За рамками статьи остались и другие техники маскировки (отдельный IP для исходящих соединений, раздельное туннелирование и прочее).
Я не призываю срочно заменять VLESS на Naive. Хороший протокол — тот, который стабильно работает прямо сейчас и не блокируется автоматически; что будет дальше, предсказать сложно.
Хорошая иллюстрация — история Reality. Пользователи долго мирились с его главным минусом: на каждое конечное соединение прокси-сервер открывает отдельное соединение с донором сертификата. Всё это делалось с расчётом на будущие проверки сертификатов. Но сертификаты так и не стали проверять, а прокси начали блокировать по IP из-за большого количества одновременных соединений. Поэтому чем больше качественных альтернатив, тем лучше. Всем удачи!
Комментарии (38)

maxscitech
18.04.2026 12:17Перехватив этот пакет, можно довольно точно определить программу, которая его отправила. Xray и sing-box написаны на Go, поэтому без дополнительных ухищрений их ClientHello соответствует стандартному для Go — такие соединения можно распознать и заблокировать.
Вообще то в конфигах спокойно можно прописать под какой браузер маскироваться. Какой еще ClientHello, стандартный для Go? Это что то новое.

hdrover Автор
18.04.2026 12:17Дочитайте, пожалуйста, подраздел до конца. Следующее предложение после процитированного вами:
Для маскировки оба проекта используют библиотеку uTLS, которая позволяет сделать ClientHello похожим на ClientHello реального браузера (Chrome, Firefox или др.).
Как раз uTLS (о котором подраздел) и обеспечивает похожий на браузерный ClientHello, если он включен через конфиг. Если не использовать uTLS, то будет стандартный ClientHello от Go (в случае программы, написанной на Go).

Ingref
18.04.2026 12:17Не затронуты плюсы и минусы по сравнению с VLESS. Но за статью спасибо.

hdrover Автор
18.04.2026 12:17Это сложно сделать из-за того, что VLESS очень сильно отличается в зависимости от настроек и транспорта (Vision, XHTTP, gRPC, Reality и прочее). И даже Vision работает сильно по-разному в зависимости от трафика, который он прогоняет (где-то включается Splice, а где-то нет).
Основное же отличие Naive я постарался описать в разделах "ClientHello и uTLS" и "О NaïveProxy". А к чему реально будет в дальнейшем привязываться цензор (какая особенность того или иного протокола будет мешать или помогать) - неизвестно. Может вообще все закончится белыми списками, а не анализом протоколов.

FlyHighOnTheSky
18.04.2026 12:17Насколько я понял из ответов ИИшки (которую мучал этим вопросом несколько недель назад) Naive по сравнению с VLESS Vision Reality:
+ Лучше маскируется
- Медленее (неизвестно на сколько)
- Нет поддержки туннелирования UDP - голос и игры могут не заработатьТ.е. если VLESS (Reality Vision) работает и устраивает - то можно не смотреть в сторону Naive или поднять второй сервер с ним на всякий пожарный, если вдруг VLESS начнут резко детектировать.

hdrover Автор
18.04.2026 12:17При связке, описанной в статье, UDP работает. Я отдельно упомянул параметр
udp_over_tcp. С клиентами на базе sing-box тоже работает. И с популярным Shadowrocket работает.По поводу скорости всё индивидуально, можно сделать замеры. ИИ так мог ответить из-за режима Splice в Vision Reality, но он скорее про нагрузку сервера, да и включается не всегда (зависит от условий). И наоборот, у Vision Reality есть принципиальная проблема (особенность) с отсутствием мультиплексирования и необходимостью на каждое новое подключение подключаться к удаленному серверу для получения сертификата, что создает существенные задержки на каждое устанавливаемое соединение (а если сайт-донор еще и тормозит или блокирует частые подключения, то становится совсем плохо).
А вот то, что переходить с VLESS на Naive нет смысла, если VLESS хорошо работает - это верно (я об этом тоже сказал в заключении статьи).

Inflame
18.04.2026 12:17Насколько я понял из ответов ИИшки
LLM лучше не спрашивать о тонкостях работы этих средств обхода блокировок без обогащения контекста документацией или исходным кодом (иначе галлюцинируют).

jtraub
18.04.2026 12:17Подскажите, пожалуйста, проблему детектирования за счёт TLS in TLS автор уже решил?

hdrover Автор
18.04.2026 12:17К сожалению, проблема TLS in TLS остается. Вот что автор пишет в своей документации:
Соединение TLS поверх TLS требует большего количества циклов обмена данными (round trips) при рукопожатии, чем необходимо для обычных HTTP/2 (h2) запросов; иными словами, ни одному h2-запросу не нужно такое количество двусторонних обменов при установке соединения. Простого способа избежать этого нет, кроме использования MITM-проксирования, что нарушает сквозное (E2E) шифрование.
Накладные расходы TLS поверх TLS приводят к заметному увеличению длины пакетов и отсутствию пакетов малого размера. Устранение этих издержек также требует MITM-проксирования.
Кроме того, из-за накладных расходов TLS поверх TLS размер пакетов постоянно превышает лимиты MTU, чего не должно происходить со стороны исходного пользовательского агента (клиента). Решение этой проблемы требует повторной сегментации (re-segmentation), что реализовать непросто.
По сути маскируется это только мультиплексированием множества конечных соединений внутри одного туннеля (поэтому автор и рекомендует
insecure_concurrency = 1), что затрудняет анализ длины и отчасти скрывает TLS in TLS.

0ka
Это всё хорошо, но расстраивает отсутствие последней версии в iOS appstore. Форк (напр sing-box-extended) выложить не получится?
hdrover Автор
Я задонатил автору sing-box через github (благодарность за хорошую программу). За это дается доступ к приватному telegram-чату с доступом к свежей версии sing-box для iOS и macOS.
0ka
Это геморно по сравнению с андроидом где взял и скачал последнюю версию, и не надо донатить и писать свой apple id. Я ему кстати тоже донатил, но он меня забанил после того как в очередной раз (хотя я лично всего 2 раза) попросил добавить amnezia wg, а ещё до этого он забанил меня за вопрос типа "почему ты постоянно блокируешь issue без объяснений? Что мешает чётко выражаться?". Вообще хотел 100$ ему закинуть, но он меня остановил на 10$ своим поведением
hdrover Автор
Согласен. Опять же нужна иностранная карта для доната. Но поддержка Naive есть не только в sing-box. В очень популярном Shadowrocket она есть. В бесплатном Karing тоже есть (ядро sing-box).
RulenBagdasis
Вы не задонатили, вы купили доступ к доп возможностям. Пожертвование, оно должно быть просто так, без получения чего-то в ответ. Иначе получится, как в РПЦ, когда, чтобы не соблюдать ЗоЗПП, всё выворачивают так, как быдто вы жертвуете деньги, а они вам в ответ нарят товар.
hdrover Автор
Я против публичного обсуждения благотворительности, но на публичное "обвинение" отвечу. Начать хотя бы с того, что доступ дается за любой единоразовый платеж. Я подключил ежемесячные платежи на хорошую сумму. Я стараюсь продвигать sing-box статьями на хабре, что идет в плюс автору (даже скорее всего финансово). Я пофиксил несколько багов в коде (один из них описан тут), PR приняты. Плюс добавил новое правило package_name_regex, будет в релизе в версии 1.14. Так что мои отношения с sing-box строятся именно на любви к продукту, а не на получении благ за деньги. Но конечно можно назвать это эгоизмом, потому что я сам пользуюсь программой и хочу сделать её лучше.
RulenBagdasis
Так а я вас ни в чём не обвиняю. Это автор ПО называет благотворительностью то, что ей не является.
Как к этому относиться, личное дело каждого. Но лично моё мнение тостоит в том, что описанная ситуация сильно попахивает. Те, кому это нужно, часто не имеют “иностранной” карты, чтобы сделать “пожертвование”. В итоге, они не имеют доступа к свежим версиям ПО. Как по мне, это что угодно, но не пожертвование.
Вы можете иметь другое мнение, это нормально.
0ka
Автор изначально ничего не просил за последнюю версию, это apple заблокировали ему аккаунт и он не может выложить новую версию
Hint
Да, у меня тоже были такие подозрения. Но даже если так, то автора не осуждаю, делает хорошее дело (судя по коммитам это для него как основная постоянная работа). Плюс очень много бесплатных клиентов используют его ядро (то есть бесплатный доступ к его коду есть). Для обычных пользователей оригинальный sing-box сложноват. В AppStore доступна устаревшая версия, потом начались какие-то проблемы. И такие проблемы у него возникают не в первый раз (потом программа все-таки обновилась, а потом снова пауза).
А проблема в том, что у Apple для VPN отдельные более жесткие правила публикации. Такая программа может публиковаться только разработчиком, зарегистрированным как organization.
Hint
В Shadowrocket есть naive
0ka
А шадоурокет нету на другие платформы. Хочется 1 конфиг и хорошую программу на все mainstream платформы, сингбокс был бы ближе всего к этому если бы не эта фигня со старой версией для ios/mac
HyperMe
hiddify рассматривали?
ZonD80
Я написал клиент для naive для iOS:
https://habr.com/ru/articles/1023230/