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

Уровни безопасности Simmetric Chat: API-ключи, подписанные webhook'и и DLP

Как Simmetric Chat аутентифицирует каждый запрос, хэширует API-ключи через HMAC-SHA256, подписывает webhook'и и Web Push и редактирует персональные данные фильтрами DLP.

Simmetric Team10 мин чтения08/09/2026

Безопасность - это стек, а не переключатель

Чат-платформа, хранящая документы вашей компании, должна заслуживать доверие слоями: как аутентифицируются запросы, как выдаётся и хранится программный доступ, как фоновые интеграции доказывают свою легитимность и что происходит с чувствительным содержимым, пока оно проходит через промпты и ответы. Simmetric Chat отвечает на каждый из этих аспектов именованным механизмом, и v0.22 закрыла некоторые из самых тонких дыр: timing-safe сравнения секретов, устойчивый к перечислению вход и DLP-движок, покрывающий теперь и структурированные европейские идентификаторы. Эта статья проходит по стеку от входной двери вглубь.

Три способа аутентификации запросов

Каждый эндпоинт под /api попадает в один из трёх режимов учётных данных:

  • JWT Bearer (основной). Люди-пользователи аутентифицируются через эндпоинт входа или регистрации и получают подписанный JWT. Каждый токен несёт claim jti, проверяемый по списку отзыва (опционально на Redis), чтобы выход или административный отзыв действовали немедленно, а не по истечении. Невалидные или истёкшие токены получают чистый 401; middleware разрешает пользователя вместе с ролями и правами на каждом запросе.
  • API-ключ (`X-Api-Key`). Программный доступ - сервисная поверхность widget'а и ключи, создаваемые пользователями через API-key эндпоинты - использует ключи с префиксом, проверяемые по HMAC-digest, описанному ниже.
  • Общий секрет collector'а. Межсервисные вызовы ingestion-collector'а несут X-Collector-Secret, сравниваемый в постоянном времени с защитой по длине. Это было последнее место, где на сервере выживало сравнение секретов в открытом виде, и v0.22 закрыла его: callbacks импорта архивов теперь используют ту же дисциплину crypto.timingSafeEqual, что и любой другой секретный барьер.

Над аутентификацией стоят RBAC-защиты, разбираемые в отдельной статье: проверки прав, admin-барьеры и защита от IDOR на доступе к workspaces и проектам. Аутентификация отвечает на «кто вы»; RBAC - на «что вам можно трогать».

API-ключи: HMAC-SHA256, шифрование at rest

API-ключ - bearer-credential, поэтому то, как сервер его хранит, важно не меньше того, как он его проверяет. Simmetric Chat выдаёт ключи с узнаваемым префиксом sk- - привычным для экосистем инструментов, которыми большинство разработчиков уже пользуется, - и никогда не хранит сам ключ. At rest каждый ключ существует только как HMAC-SHA256-digest, вычисленный под выделенным серверным секретом API_KEY_HMAC_SECRET:

text
sk-abc123… (выдан один раз, показан вызывающему один раз)
 │  HMAC-SHA256(API_KEY_HMAC_SECRET, ключ)
 ▼
key_hash хранится в api_keys - сам ключ невосстановим

У дизайна два намеренных свойства:

  • Развязанная ротация. API_KEY_HMAC_SECRET независим от JWT_SECRET и ENCRYPTION_KEY. Ротация ключа подписи сессий не инвалидирует API-ключи, а ротация ключа шифрования at rest не ломает проверку ключей. У каждого секрета одна задача.
  • Проверка в постоянном времени. Проверка - это поиск по ключеванному HMAC-digest: O(1), без лимитов take на сканирование кандидатов. Именно это делает аутентификацию по API-ключу достаточно дешёвой, чтобы стоять на каждом запросе в многоинстансном развёртывании.

Пользователи управляют своими ключами через API-key эндпоинты: создание по требованию, листинг по запросу, отзыв по запросу. Отзыв убирает возможность восстановить валидный credential; digest больше ничему не соответствует.

Подписанные webhook'и и Web Push

Исходящие интеграции должны быть проверяемы так же, как входящие.

Webhook'и подписываются HMAC-SHA256. Сервер вычисляет подпись по payload с секретом webhook'а, а ваш принимающий сервис пересчитывает digest, прежде чем доверять телу события. Принимающий эндпоинт никогда не должен доверять вызывающему, называющему себя Simmetric Chat: он может это доказать, байт за байтом, своей копией секрета. Эндпоинт тестовых событий позволяет прогнать получателя, не порождая реальной активности на платформе.

Web Push использует протокол VAPID для браузерных уведомлений. Сервер держит пару ключей VAPID; публичный ключ экспонируется аутентифицированным клиентам через системный эндпоинт, подписки управляются явными эндпоинтами subscribe/unsubscribe, а администраторы могут отправить тестовый push для сквозной проверки конвейера. Оба канала всегда активны на уровне Community: подпись и push - базовое поведение платформы, а не enterprise-функция.

Rate limiting на границе

Rate limiting расслоён по поверхностям, с обычными заголовками RateLimit-* на ограниченных маршрутах:

  • Глобальный API-лимитер - 200 запросов в минуту на IP по всем маршрутам в продакшене
  • Лимитер аутентификации - 10 запросов в минуту на пишущих эндпоинтах аутентификации, самый узкий барьер, потому что credential-эндпоинты - первые цели абьюза
  • Lead-лимитер widget'а - 3 запроса в час на захвате лидов, потому что публичная форма - место концентрации автоматизированного абьюза
  • Probe-лимитер - 10 запросов в минуту на эндпоинтах проверки связности, чтобы тестирование мастера настройки нельзя было превратить в оружие

Когда задан REDIS_URL, счётчики живут в общем Redis-хранилище, так что лимиты значат одно и то же на каждом инстансе; иначе каждый инстанс держит своё хранилище. Запросы с заголовком widget'а пропускают глобальный лимитер: widget-трафик уже throttled'ится выше по потоку per-key лимитером widget-сервиса, - а выделенного чат-лимитера нет, потому что агент внутри себя обеспечивает параллелизм на пользователя, бюджеты токенов и таймауты по стенным часам.

DLP: редакция до эксфильтрации

Data Loss Prevention в Simmetric Chat - плагин-фильтр, сканирующий и входящий промпт, и исходящий ответ, включая прогрессивные потоковые сбросы токен-за-токеном, и редактирующий совпадения до того, как содержимое покинет вашу сеть. Сканер распознаёт 10 встроенных классов PII-паттернов:

  • Адреса электронной почты
  • Номера кредитных карт
  • API-ключи и приватные ключи
  • Плюс структурированные европейские идентификаторы: итальянские Partita IVA, codice fiscale и IBAN, добавленные в v0.22 и идемпотентно засеянные

Конфигурация паттернов хранится в базе и управляется админами: включайте и отключайте любой паттерн построчно, добавляйте до 50 пользовательских паттернов с живой валидацией компиляции и тестовым превью, изучайте панель истории совпадений DLP с фильтром по источнику (чат или widget). Встроенные регулярные выражения заморожены - встроенный паттерн можно отключить, но не переписать, - а пользовательские несут ваши определения. Сканирования, которые могут прочитать настроенные паттерны, используют их через короткий TTL-кэш и откатываются на встроенный набор, если база недостижима, так что сбой базы никогда не отключает редакцию.

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

Самое тонкое усиление в v0.22

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

  • Timing-safe сравнения повсюду. Каждое оставшееся сравнение секретов в открытом виде - барьеры секрета collector'а, callback импорта архивов, проверка cache-bust ключа widget'а - теперь использует crypto.timingSafeEqual с защитой по длине и fail-closed поведением, когда ожидаемый секрет не задан.
  • Устойчивый к перечислению вход. Когда имени пользователя не существует, вход всё равно выполняет фиктивное сравнение хэша до ответа, так что время ответа больше не различает существующих и несуществующих пользователей. Невалидные тела возвращают структурный 400, а не 401, который выпустил бы внутренности Zod.
  • Громко падающие миссконфигурации. Серверная HMAC-миссконфигурация на проверке API-ключей возвращает 500, намеренно: неверно настроенный секрет никогда не должен маскироваться под сбой аутентификации.
  • Структурная валидация. Тела запросов валидируются общими Zod-схемами через safeParse; каждая ошибка - единый конверт с деталями по полям, чтобы клиенты падали предсказуемо.

Вся API-поверхность - таблицы эндпоинтов, рамки SSE-событий и требования аутентификации по маршрутам - задокументирована в API-справочнике, и живой интерфейс Swagger включён в сервер.

Читайте полное руководство в документации →

Похожие статьи