Skip to content

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

можно. использует несколько уровней защиты: JWT-аутентификацию для веб-панели, API-ключи для SDK, rate limiting для предотвращения атак, и security-заголовки для защиты браузера.

Аутентификация

JWT (веб-панель и REST API)

Алгоритм: HMAC-SHA256. Структура токена:

json
{
  "sub": "1",
  "email": "admin@example.com",
  "role": "ADMIN",
  "iss": "mozhno",
  "iat": 1719000000,
  "exp": 1719000900
}
ПараметрПо умолчаниюОписание
Access token TTL15 минутJWT_ACCESS_TOKEN_TTL_MINUTES
Refresh token TTL30 днейJWT_REFRESH_TOKEN_TTL_DAYS
СекретОбязателен в продеJWT_SECRET, минимум 256 бит
ИздательmozhnoJWT_ISSUER

Refresh Token Rotation (семейная ротация)

При обновлении access-токена:

  1. Старый refresh-токен инвалидируется
  2. Генерируется новый refresh-токен в ту же «семью» (family)
  3. Если украденный токен используется повторно — вся семья аннулируется
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: POST /api/v1/auth/refresh { refreshToken: "A1" }
    Server->>Server: Ищем A1 в семье α
    Server->>Server: Инвалидируем A1
    Server->>Server: Генерируем A2 (семья α)
    Server-->>Client: { token, refreshToken: "A2" }

    Note over Client: Злоумышленник использует A1

    Client->>Server: POST /api/v1/auth/refresh { refreshToken: "A1" }
    Server->>Server: A1 найден, но уже использован!
    Server->>Server: Аннулируем ВСЮ семью α
    Server-->>Client: 401 TOKEN_REUSE

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

API-ключи (SDK)

Ключ передаётся как Bearer-токен: Authorization: Bearer <api-key>. Тип ключа определяет доступные операции:

ТипДоступ
SERVERGET /api/client/features, POST /api/client/metrics
FRONTENDPOST /api/client/evaluate, POST /api/client/metrics

Подробнее — API-ключи.

BCrypt

Пароли хешируются BCrypt со сложностью 12 раундов. Это означает ~0.3 секунды на проверку пароля — достаточно медленно для защиты от перебора, достаточно быстро для комфортного логина.

Rate Limiting

Используется алгоритм Token Bucket (Bucket4j). Лимиты применяются к IP-адресу клиента:

ЭндпоинтЁмкостьПополнениеИнтервал
POST /api/v1/auth/login5+51 мин
POST /api/v1/auth/forgot-password, /reset-password, /accept-invite3+360 мин
POST /api/v1/auth/refresh10+101 мин
POST /api/client/* (SDK)1000+10001 мин
POST/PUT/DELETE /api/v1/* (admin write)100+1001 мин

При превышении возвращается 429 RATE_LIMIT_EXCEEDED.

Все лимиты настраиваются через переменные окружения — см. Конфигурацию.

Защита браузера

CORS

Настраивается через APP_CORS_ALLOWED_ORIGINS. Для продакшена укажите конкретный домен:

APP_CORS_ALLOWED_ORIGINS=https://app.example.com

Security-заголовки

ЗаголовокЗначение
Strict-Transport-Securitymax-age=31536000 (1 год)
Content-Security-PolicyНастроен для защиты от XSS

Рекомендации для продакшена

РекомендацияКак сделать
Сложный JWT_SECRETopenssl rand -base64 32
HTTPS-onlyИспользуйте обратный прокси (Nginx, Traefik, Caddy) с TLS
Ограниченный CORSУкажите конкретный домен, не *
Secrets managerНе храните пароли и ключи в docker-compose.yml
Ротация ключейAPI-ключи — раз в квартал; JWT_SECRET — при смене команды
Не запускайте от rootDocker: user: '1000:1000', read-only FS
Логирование без секретовSensitiveDataMasker маскирует JWT, ключи, пароли в логах

Что дальше?

Released under the AGPL v3.0 License.