NaïveProxy в sing-box (альтернатива VLESS)

от автора

Читая статьи про прокси, можно подумать, что 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).

Утечка вместо нулей в padding

Утечка вместо нулей в padding

Настройка клиента 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 из-за большого количества одновременных соединений. Поэтому чем больше качественных альтернатив, тем лучше. Всем удачи!

ссылка на оригинал статьи https://habr.com/ru/articles/1024990/