Активное зондирование: почему сервер должен молчать одинаково

Пассивный анализ только помечает адрес — дальше цензор подключается сам. Чем выдаёт себя сервер, который «просто не отвечает», и почему молчать надо консистентно.

2026-08-31 GIGATAP Team #vpn
#vpn#anticensorship#probing#opsec#shadowsocks

Активное зондирование: почему сервер должен молчать одинаково

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

Двухступенчатая схема#

Полный анализ каждого соединения дорог. Поэтому применяется дешёвая схема из двух ступеней.

1. ПАССИВНО: дешёвые признаки на потоке
   энтропия, длины первых пакетов, отсутствие маркеров
        │
        ▼ адрес помечен подозрительным
        │
2. АКТИВНО: отдельная инфраструктура подключается сама
   отправляет подготовленные запросы, смотрит на ответ
        │
        ▼
   ответ отличительный? ──► адрес в блок-лист

Первая ступень отсеивает почти всё и работает на потоке. Вторая дорогая, но применяется к малой доле адресов.

Исследование блокировки Shadowsocks описало эту схему в деталях: подозрение возникало по длине и энтропии первого пакета данных, после чего к адресу шли зонды нескольких типов, причём с тысяч разных адресов.

Почему наивной защиты мало?#

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

Этого недостаточно, и причина тонкая.

Работа, представленная на NDSS в 2020 году, показала: несколько систем, специально спроектированных против зондирования, всё равно различались — не по содержимому ответа, а по поведению сетевого стека при закрытии соединения. Флаги TCP и тайминги закрытия давали достаточно, чтобы отличить их друг от друга и от обычных сервисов.

Иначе говоря: сервер, который правильно молчит на прикладном уровне, выдаёт себя тем, как именно он молчит.

Что сравнивает зонд Почему различает
Через сколько закрылось соединение таймаут — характерная константа реализации
Какими флагами закрылось RST против FIN — разные стеки ведут себя по-разному
Сколько байт успело прийти до закрытия выдаёт, сколько парсер успел прочитать
Одинаково ли на разные типы мусора различие само является признаком

Три требования#

Отсюда вырастают конкретные правила, и все три встречаются в спецификациях зрелых протоколов.

Читать дальше при ошибке. Не завершать соединение в момент обнаружения неверной аутентификации, а продолжать читать. Завершение в характерный момент — сигнал само по себе.

Закрывать консистентно. Одинаковые флаги и тайминги для любого некорректного входа. Различие между «неверный пароль» и «мусор» не должно быть наблюдаемым.

Не раскрывать, сколько прочитано. Спецификация Shadowsocks 2022 прямо требует, чтобы поведение при закрытии не выдавало число потреблённых парсером байт — иначе побайтовая проба находит длину секретного префикса двоичным поиском.

ПЛОХО — оракул длины
зонд: 1 байт мусора    → мгновенный RST
зонд: 16 байт мусора   → мгновенный RST
зонд: 32 байта мусора  → пауза 3 с, потом FIN  ← парсер дошёл сюда
                                                  длина префикса найдена

ХОРОШО — поведение не зависит от входа
зонд: любой мусор      → одинаковое поведение, одинаковый тайминг

Защита от повтора#

Отдельный вектор: захваченное рукопожатие законного пользователя — готовый зонд.

Цензор может воспроизвести записанный обмен и посмотреть, ответит ли сервер так же. Наблюдения показывают, что воспроизведение случается и немедленно, и спустя недели.

Отсюда требование к фильтру повторов: он проверяет и одноразовое значение, и метку времени. Только по времени — не поймает немедленный повтор. Только по одноразовому значению — не переживёт перезапуск сервера.

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

Запасной путь: свой сайт или чужой#

У маскировки под TLS есть развилка, влияющая на устойчивость к зондированию.

Схема Что отвечает зонду Риск
Свой сайт за тем же адресом ваш веб-сервер, поведение под контролем нужен работающий сайт
Заимствованный чужой сайт чужой сервер, поведение вам не подчиняется смена его политики уводит вас в серый список

Второй вариант зависит от третьей стороны. Наблюдения за иранской инфраструктурой описывают ведение серого списка по признаку «сервер не ответил как ожидалось» — а ответит ли заимствованный сайт, вы не контролируете.

Практический критерий при выборе цели маскировки: отвечает ли она стабильно и предсказуемо на запрос произвольного клиента. Единичная проверка тут ничего не доказывает — нужна серия.

Что проверить у себя#

Короткий список, проверяемый за один сеанс:

Одинаково ли поведение на разные типы неверного входа. Пустой запрос, случайные байты, обрезанное рукопожатие, корректный префикс с неверным окончанием.

Совпадает ли поведение с эталонным веб-сервером. Сравнивать не «отвечает или нет», а распределение: коды, флаги закрытия, задержки.

Переживает ли фильтр повторов перезапуск. Кэш в памяти обнуляется при рестарте — и окно повтора открывается.

Стабильна ли цель маскировки. Серия запросов, а не один.

Вывод#

Зондирование — вторая половина задачи маскировки, и она про сервер, а не про трафик.

Ключевая формулировка короткая: отсутствие ответа — тоже ответ. Сервер, который молчит характерным образом, различим не хуже, чем сервер, который отвечает характерным баннером.

Цель не в том, чтобы молчать, а в том, чтобы молчать так же, как молчит что-то обычное — и одинаково на всё, что не является законным клиентом.

Термины#

  • Активное зондирование - подключение цензора к серверу напрямую с целью определить, что на нём работает.
  • Оракул длины - различие в поведении при закрытии, по которому определяется, сколько байт успел прочитать парсер.
  • Фильтр повторов - механизм, отвергающий воспроизведение ранее записанного рукопожатия.

FAQ: частые вопросы#

Достаточно ли просто не отвечать?#

Нет. Различимы тайминги и флаги закрытия соединения, поэтому сервер выдаёт себя тем, как именно он молчит.

Зачем фильтру повторов и метка времени, и одноразовое значение?#

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

Свой сайт или чужой в качестве запасного пути?#

Свой. Поведение чужого сервера вам не подчиняется, и смена его политики уводит вас в серый список.

Что читать дальше#