Безопасность

Обновлено:

TURN сервер по своей природе принимает пакеты из интернета и пересылает их на другие адреса. Поэтому неправильно защищенный TURN сервер может стать мишенью для двух угроз: несанкционированного расхода трафика чужими приложениями и SSRF атак на внутреннюю инфраструктуру. В Slyber Turn Server обе проблемы решены на уровне архитектуры.

1. Временные криптографические учетные данные

Slyber Turn Server не хранит базу пользователей на диске и не требует походов в БД при каждом подключении. Используется стандартная для WebRTC схема временных токенов:

  • Имя пользователя (username): состоит из времени истечения токена (Unix timestamp в секундах) и идентификатора пользователя, разделенных двоеточием: <expiration_timestamp>:<user_id> (например, 1761580000:user_777).
  • Пароль (password): вычисляется по формуле Base64(HMAC-SHA1(TURN_SECRET, username)).

Когда клиент подключается к TURN-серверу:

  1. Сервер проверяет формат username и убеждается, что текущее время не превысило expiration_timestamp.
  2. Сам вычисляет HMAC-SHA1 от username с использованием своего TURN_SECRET и проверяет подпись пакета.
  3. Как только время TTL истекает, учетные данные автоматически становятся недействительными.

2. Эшелонированная защита HTTP API (/api/turn-credentials)

Вы можете гибко комбинировать 4 уровня защиты эндпоинта выдачи учетных данных:

Уровень А: Секретный ключ (X-Turn-Secret / Bearer)

Запрос может содержать заголовок X-Turn-Secret: <ваш_TURN_SECRET> или Authorization: Bearer <ваш_TURN_SECRET>.

  • Проверка ключа выполняется за константное время через subtle.ConstantTimeCompare, что полностью исключает атаки по времени.
  • Если включен REQUIRE_SECRET=true, запросы без этого заголовка немедленно отклоняются с кодом 401 Unauthorized.
  • Наличие валидного секретного ключа дает привилегии: обходит лимиты Rate Limiter, фильтры CORS/IP и позволяет запрашивать кастомный ?ttl=, превышающий стандартный CREDENTIAL_TTL_SEC.

Уровень Б: Белый список IP и подсетей

Если задан ALLOWED_IPS (например, 198.51.100.25, 10.20.0.0/16), запросы без секретного ключа разрешаются только с указанных IPv4/IPv6 адресов или CIDR подсетей (остальные получают 403 Forbidden).

Уровень В: Умный валидатор CORS

Если запрос идет напрямую из браузера (без секретного ключа и без жесткого ограничения ALLOWED_IPS), сервер проверяет заголовок Origin:

  • Поддерживается точное совпадение домена и схемы (например, https://exmaple.com).
  • Автоматическая поддержка поддоменов: если в ALLOWED_ORIGINS указан https://exmaple.com, валидатор автоматически разрешит запросы с любого поддомена по той же схеме, например https://rtc.example.com или https://app.example.com.

Уровень Г: Защита от флуда

Для всех запросов без секретного ключа работает встроенный по IP ограничитель частоты запросов на базе алгоритма Token Bucket:

  • Скорость пополнения: 2.0 запроса в секунду с одного IP.
  • Максимальный всплеск: до 10 запросов подряд. При превышении возвращается 429 Too Many Requests.
  • Защита памяти от DDoS: таблица хранит максимум 50 000 уникальных IP адресов и каждые 2 минуты автоматически очищает записи старше 2 минут.

Безопасная работа за Reverse Proxy (Nginx / Caddy)

Сервер защищен от подделки заголовков X-Forwarded-For и X-Real-IP: он доверяет этим заголовкам только тогда, когда физическое TCP соединение пришло с локального интерфейса (127.0.0.1 / ::1, то есть от вашего локального Nginx) или когда запрос авторизован валидным X-Turn-Secret.

3. Встроенная защита от SSRF атак

В протоколе TURN клиент указывает, на какой IP адрес (Peer IP) сервер должен переслать пакет. Злоумышленник может попытаться указать вместо адреса собеседника внутренний адрес вашей базы данных (10.0.0.42), локальный порт сервера (127.0.0.1) или сервис метаданных облака AWS/GCP (169.254.169.254).

В Slyber Turn Server встроен фильтр PeerFilter, который проверяет каждое разрешение (PermissionHandler) и разделяет блокировки на две категории:

Категория 1: Критические SSRF угрозы

Попытки обращения к этим адресам жестко блокируются, увеличивают счетчик атак turn_ssrf_blocked_total, записываются в журнал безопасности и заносят IP клиента в список нарушителей (top_offenders) с пятикратным штрафным весом:

  • Loopback-адреса: 127.0.0.0/8, ::1.
  • Системная сеть «This Network»: 0.0.0.0/8 (популярный вектор обхода фильтра 127.0.0.1).
  • Link Local и Cloud Metadata (AWS / GCP / DigitalOcean / Azure): 169.254.0.0/16 (включая 169.254.169.254), IPv6 AWS IMDS fd00:ec2::254/128, fe80::/10.
  • Широковещательные, многоадресные и неопределенные адреса: 255.255.255.255, 0.0.0.0, Multicast.
  • Собственные локальные сетевые интерфейсы самого TURN-хоста: сервер при старте сканирует все свои сетевые карты (net.InterfaceAddrs()) и запрещает обращаться к своим внутренним IP.

Категория 2: Локальные кандидаты браузера

При установке WebRTC соединения браузеры часто по ошибке пытаются проверить через TURN локальные домашние адреса собеседника (например, 192.168.1.1). Это не хакерская атака, а штатное поведение WebRTC ICE. Чтобы не засорять журнал ложными тревогами, PeerFilter отклоняет такие пакеты, но учитывает их в отдельном счетчике lan_skipped:

  • Приватные сети RFC 1918 и IPv6 ULA (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7).
  • Сети операторского NAT / Tailscale (CGNAT 100.64.0.0/10).
  • Документационные, тестовые и зарезервированные подсети (192.0.0.0/24, 192.0.2.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, 2001:db8::/32, 2001::/32, 2002::/16, 64:ff9b::/96).

Поддержка TURN Hairpinning

При этом фильтр явно разрешает пересылку пакетов на собственный публичный адрес сервера (PUBLIC_IP). Это необходимо для сценария TURN Hairpinning - когда оба участника звонка находятся за строгими NAT и оба подключены к одному и тому же TURN серверу, пересылая медиа потоки между двумя релейными портами этого сервера.