Аутентификация JWT, Redis, Secret и сквозное шифрование SFrame E2EE

Обновлено:

Безопасность в Slyber SFU Server разделена на три независимых контура. Первый контур проверяет права клиентов при входе в комнату (через JWT, Redis или HMAC Secret). Второй контур защищает внутренние административные шлюзы и телеметрию с помощью выделенного ключа NODE_SECRET. Третий контур обеспечивает сквозное шифрование медиапакетов по стандарту RFC 9605 SFrame и ограничивает входящий битрейт каждого участника.

Три режима аутентификации клиентов (AUTH_MODE)

Выбор режима проверки клиентских токенов задается переменной окружения AUTH_MODE или флагом -auth-mode (значения параметров запуска приведены в статье Запуск в Docker и переменные окружения). Во всех режимах сверка подписей и секретов выполняется за константное время через хеширование SHA256 и функцию subtle.ConstantTimeCompare, что полностью исключает атаки по времени отклика.

1. Режим JWT (по умолчанию)

В режиме jwt сервер проверяет токены стандарта HS256, подписанные секретным ключом JWT_SECRET. Полезная нагрузка токена должна соответствовать структуре TokenClaims.

JSON
{
  "sub": "user-101",
  "room_id": "conference-alpha",
  "profile": "conference",
  "iat": 1763090000,
  "exp": 1763093600,
  "require_e2ee": false,
  "caps": {
    "can_publish": true,
    "can_subscribe": true,
    "can_use_data": true,
    "max_spatial_layer": 2,
    "max_bitrate_kbps": 3500,
    "allowed_transports": ["udp", "tcp", "turn"]
  }
}

Поле exp (время истечения срока действия в формате Unix timestamp) является строго обязательным. Токены с пустым или нулевым полем exp автоматически отвергаются сервером. Поле room_id привязывает токен к конкретной комнате (либо принимает значение * для доступа к любой комнате). Вложенный объект caps позволяет тонко ограничить права участника, например выдать зрителю вебинара токен только на просмотр с флагом can_publish в значении false (при таком токене сервер заблокирует любую попытку отправить SDP оффер с атрибутами a=sendonly или a=sendrecv).

2. Режим Redis (динамические сессии с мгновенным отзывом)

В режиме redis сервер использует встроенный пул постоянных TCP соединений к вашей базе Redis и ищет ключ вида slyber:session:<TOKEN>. Перед отправкой запроса токен проверяется на отсутствие пробелов и символов перевода строки для защиты протокола RESP от инъекций. Значением ключа в Redis может быть как простая строка с идентификатором участника (тогда ему выдаются полные права по умолчанию), так и полная JSON строка со структурой TokenClaims. Удаление ключа из Redis позволяет мгновенно отозвать доступ пользователя.

3. Режим Secret (временные HMAC SHA1 токены)

В режиме secret токен формируется без обращения к базе данных по формуле <EXPIRES_UNIX>:<PARTICIPANT_ID>:<BASE64_HMAC_SHA1>, где подпись вычисляется от строки <EXPIRES_UNIX>:<PARTICIPANT_ID> с использованием ключа TURN_SECRET.

Внешние серверы TURN и генератор тестовых токенов

Slyber SFU Server не включает внутрь себя тяжелый TURN релей, а работает в связке с внешними серверами (например с выделенным узлом Slyber TURN Server). Если в конфигурации заданы переменные EXTERNAL_TURN_URLS и TURN_SECRET, то при каждом входе участника в комнату (а также в HTTP заголовках Link при запросах WHIP и WHEP) сервер автоматически генерирует временные учетные данные по спецификации TURN REST API (логин вида timestamp:participant_id и пароль HMAC SHA1).

Для быстрой генерации готовых токенов со стороны вашего бэкенда предусмотрен защищенный эндпоинт GET /auth/token?room=<ROOM_ID>&user=<USER_ID>. Запрос к нему требует заголовок X-Slyber-Node-Secret и возвращает JSON с готовым jwt_token, turn_hmac_token и массивом ice_servers. Также обратите внимание, что полное принудительное закрытие комнаты со всеми участниками через сигнальное сообщение leave с полем track_id равным * разрешено исключительно административному токену с идентификатором sub равным node-admin.

Защита от флуда и ограничение битрейта (TrafficPolice)

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

  • Лимит на отдельный медиапоток по его SSRC (MAX_KBPS_PER_TRACK).
  • Суммарный лимит на все потоки одного участника по его сессии (MAX_KBPS_PER_SESSION).

Если участник превышает разрешенную полосу пропускания, лишние пакеты отбрасываются до попадания в комнату, а счетчик отброшенных пакетов фиксируется в метрике ratelimit_drops. Таблица бакетов ограничена 16384 записями с автоматической очисткой неактивных записей старше 60 секунд.

Сквозное шифрование SFrame E2EE и ротация ключей MLS

Когда для комнаты включен флаг RequireE2EE (через глобальную настройку REQUIRE_E2EE=true или через поле require_e2ee внутри токена участника), сервер переходит в режим нулевого доверия и блокирует любые незашифрованные медиапакеты (за исключением внутренних пакетов от доверенного ИИ шлюза ProtoAIPipe).

Валидатор TrackE2EEValidator обеспечивает промышленную проверку пакетов RFC 9605 SFrame без расшифровки самого медиаконтента.

  • Блокировка до регистрации ключа. Сразу после публикации трека список разрешенных ключей пуст, и любые пакеты отвергаются до тех пор, пока издатель не зарегистрирует активный KeyID.
  • Бесшовная ротация ключей MLS (e2ee_key_ratchet). Издатель отправляет сигнальное сообщение e2ee_key_ratchet со списком своих ssrcs, новым идентификатором e2ee_key_id и опциональным пакетом mls_key_package (размером до 16 КБ). Сервер проверяет, что указанные SSRC действительно принадлежат этому участнику, увеличивает номер эпохи комнаты e2ee_epoch и рассылает новый ключ остальным участникам. Для каждого трека хранится до 16 активных ключей с независимыми счетчиками, поэтому при смене ключа на новый KeyID со сброшенным счетчиком Counter = 0 поток не прерывается.
  • Поддержка фрагментации и анти реплей. Стартовый пакет кадра обязан содержать валидный заголовок SFrame и минимум 16 байт криптографического тега GCM, а последующие фрагменты того же кадра (с тем же RTP Timestamp, до 256 фрагментов на кадр) пропускаются по кешу проверенных кадров. Дубликаты и повторно отправленные пакеты отсекаются скользящим битовым окном на 512 RTP номеров и 64-битным окном счетчиков SFrame.
  • Маршрутизация слоев по RFC 9626 Frame Marking. Поскольку полезная нагрузка видео зашифрована сквозным ключом, сервер считывает признак ключевого кадра IsKeyFrame, а также индексы пространственного и временного слоев из открытого RTP расширения urn:ietf:params:rtp-hdrext:framemarking (поддерживаются профили 0xBEDE и 0x1000).