Защита слепого ретранслятора от злоупотреблений

AeroNyx8 мин чтения

Ограничения, которые узел AeroNyx применяет перед пересылкой зашифрованного трафика ретрансляции: ограничение частоты от предыдущего перехода и карантин, подавление повторов маршрутов с сохранением при перезапуске, ограниченные повторные попытки и допуск по CPU — только на основе подписанных метаданных и агрегированных счётчиков.

Защита слепого ретранслятора от злоупотреблений (Blind Relay Abuse Guard) — это набор ограничений, которые узел AeroNyx применяет, прежде чем пересылать зашифрованный трафик ретрансляции для другого узла. Она сдерживает злонамеренные или нестабильные пиры, используя только подписанные метаданные маршрутизации и локальные счётчики. Она никогда не разбирает шифротекст, не хранит историю маршрутов и не раскрывает, кто с кем общается.

Область действия

МеханизмСостояние
Пересылка непрозрачной полезной нагрузкиРеализовано
Подписанные проверки свежести и подавление повторов маршрутовРеализовано. Состояние защиты от повторов сохраняется при перезапуске, когда включено хранилище ретранслятора чата узла
Ограничение частоты запросов от предыдущего перехода и карантинРеализовано
Общепроцессные ограничения допуска запросов и криптооперацийРеализовано
Агрегированные данные о работе в состоянии узла и в NodeboardРеализовано
Проверка открытого текста или полезной нагрузкиНе выполняется, по замыслу
Аналитика по пользователям, маршрутам или социальному графуНе выполняется, по замыслу

Правило слепого узла

Ретранслятор может аутентифицировать метаданные маршрутизации, применять ограниченную политику, пересылать непрозрачный конверт и возвращать подписанную квитанцию. Он никогда не должен проверять полезную нагрузку или раскрывать метаданные, по которым можно восстановить маршрут, идентичность пользователя или связь между пользователями. В частности, ретрансляторы не записывают и не раскрывают:

  • открытый текст сообщений, пакетов, медиаданных или памяти
  • DNS-запросы, места назначения, домены, URL или историю просмотра
  • идентификаторы маршрутов, полные пути, URL эндпоинтов или IP-адреса клиентов
  • полные открытые ключи, идентичности получателей, идентификаторы сообщений или рёбра социального графа
  • закрытые ключи, секреты ваучеров, трафик на уровне кошельков или материалы для расшифровки

Конвейер допуска

Каждый запрос проходит следующие проверки, прежде чем сможет использовать ресурсы пересылки. Шаги 1–6 выполняются в указанном порядке. На шаге 7 запрос, адресованный этому узлу, переходит к его собственной конечной или луковой обработке, а запрос для другого узла резервируется после определения его следующего перехода.

text
1. request gate: process-wide admission window and in-flight limit (64 requests)
2. crypto admission: a free slot for signature and onion work, or Backpressure
3. authenticate the signed previous hop and envelope
4. previous-hop rate limit and quarantine check
5. envelope metadata: size, age and future-skew limits
6. self-loop check
7. route loop, TTL and next-hop descriptor checks, plus the route replay reservation
8. forward the opaque ciphertext, or peel the terminal layer and deliver

Каждое решение принимается на основе подписанных метаданных маршрутизации и локального агрегированного состояния, а не расшифрованного содержимого.

Ограничения во время работы

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

КонстантаПо умолчанию
BLIND_RELAY_ROUTE_REPLAY_CAPACITY8192 активных маршрута
BLIND_RELAY_ROUTE_REPLAY_TTL_SECS600 секунд
PREVIOUS_HOP_RATE_LIMIT на PREVIOUS_HOP_RATE_WINDOW_SECS120 запросов за 60 секунд
PREVIOUS_HOP_FAILURE_THRESHOLD на PREVIOUS_HOP_FAILURE_WINDOW_SECS12 учитываемых сбоев за 300 секунд
PREVIOUS_HOP_QUARANTINE_SECS300 секунд
MAX_PREVIOUS_HOP_BUCKETS4096 корзин
BLIND_RELAY_MAX_ENVELOPE_AGE_SECS600 секунд
BLIND_RELAY_MAX_FUTURE_SKEW_SECS120 секунд
BLIND_RELAY_DELIVERY_RECEIPT_MAX_AGE_SECS120 секунд
DEFAULT_MAX_ATTEMPTS (повторы пересылки)3 попытки
MAX_IN_FLIGHT_BLIND_RELAY_REQUESTS64 запроса

Ограничение частоты от предыдущего перехода и карантин

Ограничения частоты привязаны к подписанной идентичности предыдущего перехода. Более 120 запросов от одного предыдущего перехода в течение 60 секунд запускают для этого перехода пятиминутный локальный карантин. Отдельная оценка сбоев запускает такой же карантин после 12 учитываемых сбоев в течение пяти минут. В оценку засчитываются только следующие причины:

text
invalid_previous_hop | invalid_signature | self_loop | route_loop | ttl_exhausted

Тайм-ауты транспорта, потерянные подтверждения, дублирующие повторы и конфликты повторов не увеличивают оценку, поэтому исправный пир не попадает в карантин из-за проблем с сетью. Хранилище корзин ограничено, а неактивные корзины вытесняются, поэтому защита не может разрастись в долгосрочный граф коммуникаций.

Повторы маршрутов и повторные попытки

Каждый запрос ретрансляции несёт идентификатор маршрута. Когда хранилище ретранслятора чата узла включено ([memchain.chat_relay] enabled = true), резервирования маршрутов и завершённые ответы хранятся в его базе данных SQLite, поэтому защита от повторов сохраняется при перезапуске. В противном случае узел использует реестр в памяти с той же ёмкостью и окном. Если все 8192 слота заняты активными маршрутами, новые маршруты отклоняются с replay_capacity, пока слоты не истекут.

Повторный идентификатор маршрута приводит к одному из четырёх исходов:

СитуацияОтветВлияние на предыдущий переход
Тот же запрос; первая попытка завершенаПовторно воспроизводится сохранённый ответ, включая квитанцию, подписанную конечным узлом, если она есть. Ничего не доставляется и не пересылается повторно (duplicate_route)Засчитывается как успех
Тот же запрос; первая попытка ещё выполняетсяHTTP 503 route_in_flight. Отправитель может повторить попыткуНет
Другой запрос с тем же идентификатором маршрутаHTTP 400 replay_conflictЗаписывается в состояние пира. Не увеличивает оценку для карантина
Тот же запрос, но сохранённому ответу больше 120 секундHTTP 409 replay_response_expired. Маршрут остаётся зарезервированным до конца своего 600-секундного окна, поэтому не может быть выполнен сноваНет

Последний исход относится к постоянному хранилищу. Подписанные квитанции действительны только как свежее доказательство, поэтому узел не воспроизводит квитанцию повторно по прошествии 120 секунд.

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

Допуск криптоопераций (примечание о ёмкости для операторов)

Проверки подписей, снятие луковых слоёв и подписание квитанций нагружают CPU, поэтому каждый процесс узла их ограничивает:

  • Всего слотов: половина потоков CPU, которые сообщает хост, с округлением вверх, не менее 4 и не более 8, поэтому даже хост с одним или двумя потоками получает 4 слота.
  • Входящие запросы: на один слот меньше общего числа, чтобы создание исходящих маршрутов и завершение квитанций всегда могли продвигаться. Таким образом, даже на самых маленьких хостах входящие запросы получают 3 слота.
  • Когда все слоты заняты: запрос немедленно отклоняется с HTTP 429 и причиной backpressure. Он не ждёт в очереди.

Поэтому на небольшом хосте ретранслятор рано сбрасывает нагрузку при всплесках. Растущий счётчик backpressure_dropped означает, что узлу нужно больше CPU или меньше трафика ретрансляции.

Агрегированные счётчики во время работы

Узлы передают в своём heartbeat грубые накопительные счётчики и временные метки свежести в разделах:

text
system_stats.discovery_status.peer_store.runtime.blind_relay
system_stats.discovery_status.peer_store.blind_relay_quality
system_stats.discovery_status.peer_store.peer_health_summary
Группа счётчиковПоля
Приём и распределениеreceived, terminal, forwarded, rejected
Проверка и защитаinvalid_signature, envelope_too_large, ttl_exhausted, no_route, invalid_endpoint, loop_detected, replay_dropped, timestamp_rejected, rate_limited, quarantined, quarantine_started
Транспорт и повторыbackpressure_dropped, forward_failed, retry_attempted, retry_succeeded, retry_exhausted
Синтетические зондыprobe_attempted, probe_succeeded, probe_failed, two_hop_probe_attempted, two_hop_probe_succeeded, two_hop_probe_failed
Реальная доставка и свежестьverified_client_onion_deliveries, last_verified_client_onion_delivery_at, last_accepted_at, last_event_at

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

Качество доказательств

Сводка качества разделяет четыре вида доказательств: принятую работу по непрозрачной ретрансляции, синтетические зонды достижимости, синтетические двухшаговые зонды и квитанции, подписанные конечным узлом, для доставок, инициированных клиентом. Для real_relay_ready требуется свежая аутентифицированная квитанция о клиентской доставке. Синтетические доказательства никогда не выдаются за пользовательский трафик.

statusЗначение
idleАктивности ретрансляции или зондов пока не было
observingНекоторые доказательства есть, но готовность не установлена
staleПрежние доказательства успеха больше не свежие
readyСвежая принятая работа или квалифицирующее доказательство при отсутствии активных проблем с транспортом
protectingСработали механизмы защиты от злоупотреблений, а ретранслятор продолжает работать
degradedСбои пересылки или зондов требуют расследования
attentionBackpressure или исчерпанные повторные попытки требуют оперативного внимания оператора

proof_scope указывает самое сильное из полученных доказательств: client_message_delivery, relay_acceptance, message_delivery, control_plane, single_hop_control_plane, attempted или none.

Состояние пиров без связей по трафику

peer_health_summary позволяет операторам найти сбойный пир или пир в карантине, не видя, кто с кем общается.

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

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

Карта исходного кода

УровеньПуть в репозитории узлаРоль
Оркестрация ретрансляцииcrates/aeronyx-server/src/api/chat_peer/blind_relay.rsШлюз запросов, допуск криптоопераций, аутентификация, проверки петель и TTL, исходы повторов, пересылка и конечная обработка
HTTP-интерфейс и ограниченияcrates/aeronyx-server/src/api/chat_peer.rsМаршруты, ограничения тела запроса и одновременных запросов, коды ошибок и группы причин
Политика против злоупотребленийcrates/aeronyx-server/src/api/chat_peer_abuse_guard.rsОграничения частоты от предыдущего перехода, оценка сбоев и карантин
Реестр повторовcrates/aeronyx-server/src/api/chat_peer_replay.rsРеестр в памяти и формат сохранённых ответов
Постоянное хранилище повторовcrates/aeronyx-server/src/services/chat_relay_blind_route_store.rsРезервирования маршрутов и ответы в SQLite
Политика повторных попытокcrates/aeronyx-server/src/api/chat_peer_retry.rsПовторяемые и окончательные сбои и тайминг повторных попыток
Счётчики и качествоcrates/aeronyx-server/src/services/peer_store.rs и services/peer_store/status.rsАгрегированные счётчики, готовность и классификация доказательств
Отчёты о состоянииcrates/aeronyx-server/src/api/vpn_health.rs и management/reporter.rsЛокальный JSON состояния и полезная нагрузка heartbeat

ПО узлов имеет открытый исходный код под лицензией AGPL-3.0 на github.com/AeroNyxNetwork/AeroNyx. О том, как строятся маршруты, см. Обнаружение узлов и зашифрованная многошаговая ретрансляция.

<!-- faq:start -->

Часто задаваемые вопросы

Может ли узел-ретранслятор читать или записывать в журнал пересылаемый трафик?

Нет. Ретранслятор проверяет подписанные метаданные маршрутизации и пересылает непрозрачный конверт. Он хранит только агрегированные счётчики и никогда — полезную нагрузку, историю маршрутов или идентичности получателей.

Что происходит, когда узел повторяет тот же маршрут?

Если первая попытка завершена, узел воспроизводит сохранённый ответ и ничего не доставляет повторно. Если первая попытка ещё выполняется, узел возвращает допускающий повтор route_in_flight. Другой запрос с тем же идентификатором маршрута отклоняется как replay_conflict.

Сохраняется ли защита от повторов при перезапуске узла?

Да, когда включено хранилище ретранслятора чата узла. В этом случае резервирования маршрутов и завершённые ответы хранятся в SQLite. Без этого хранилища узел использует реестр в памяти, который очищается при перезапуске.

Почему пир попадает в карантин?

Пир попадает в карантин на пять минут после отправки более 120 запросов за 60 секунд или после 12 учитываемых сбоев проверки за пять минут. Тайм-ауты, потерянные подтверждения и дублирующие повторы не считаются сбоями.

Почему мой узел возвращает backpressure под нагрузкой?

Все его слоты для криптоопераций ретрансляции были заняты. Узел выделяет для работы с подписями и луковыми слоями примерно половину потоков CPU (не менее 4 и не более 8) и немедленно отклоняет избыточные запросы, а не ставит их в очередь.

<!-- faq:end -->