Перейти к содержанию

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

Безопасность встроена, а не «прикручена сверху». На этой странице собраны меры, которые реализованы в коде.

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

Мера Подробности
eID — единственный вход Единственный интерактивный способ входа — eID (QR / App2App / push по регистрационному номеру). Поверхности паролей нет вообще
JWT access + refresh refresh-токены ротируются; защищены claim kind
Список запрещённых при выходе При выходе jti access-токена помещается в Redis на остаток TTL; middleware проверяет его на каждом запросе
Сертификат гражданина (PKI) По завершении входа возвращается сертификат гражданина (DER), разбирается через crypto/x509; серийный номер, срок действия и издатель сохраняются
Привязка Google Только привязка — по стабильному столбцу subject

Отсутствие паролей — осознанное решение

Поскольку парольного потока нет, такие меры, как HIBP / bcrypt / проверка утёкших паролей, неприменимы. Устаревшие usecase с паролями и OTP остались в дереве кода, но недоступны ни по одному маршруту. Если парольный путь когда-нибудь снова откроют, подключите проверку HIBP до релиза.

Слой данных

  • Только параметризованные запросы (pgx) — без конкатенации строк, без ORM.
  • Row-Level SecurityENABLE и FORCE на каждой пользовательской таблице: users, organizations, organization_memberships, гражданские таблицы gov_* и user_integrations. Политики опираются на GUC app.user_id / app.user_role, задаваемые в каждой транзакции через SET LOCAL.
  • Нет личности ⇒ ноль строк (fail-closed), что защищает от случайного раскрытия.

Проверка RLS при старте

При запуске приложение проверяет собственную роль в базе. В продакшене роль суперпользователя или с BYPASSRLS прерывает старт — иначе RLS молча не применялся бы. В разработке выводится только предупреждение.

Каждой новой пользовательской таблице нужны собственные политики.

Секреты и шифрование

Что Как
OAuth-токены сторонних сервисов Запечатываются AES-256-GCM перед сохранением (INTEGRATION_ENC_KEY)
Идентификаторы токенов / сессий crypto/rand с отбраковкой значений, чтобы избежать смещения по модулю
MFA суперадмина (TOTP) Тоже шифруется ключом INTEGRATION_ENC_KEY

Никогда не меняйте INTEGRATION_ENC_KEY на месте

Смена уже используемого ключа сломает все ранее зашифрованные значения. Скрипт развёртывания записывает его один раз, только если он отсутствует (идемпотентно).

Веб- и сетевой слой

  • Заголовки безопасности — CSP default-src 'none', HSTS (прод), nosniff, X-Frame-Options: DENY, Referrer-Policy, Permissions-Policy, COOP/CORP/COEP.
  • CORS — строгий список разрешённых origin; никогда * вместе с credentials.
  • Ограничение размера тела — общий лимит плюс 4 КиБ на /auth.
  • Таймаут на запрос — обычно 30 с; для /ai/* — 50 с (TTS/STT в Gemini обычно занимает 10–20 с и не укладывается в 30 с).
  • Полные таймауты сервераReadHeader 10 с, Read 30 с, Write 70 с, Idle 120 с, MaxHeaderBytes 16 КиБ (защита от slowloris и огромных заголовков).
  • Ограничение запросов/auth ~5/мин, /ai/* ~20/мин, анонимный чат на главной /public/ai/chat ~6/мин — на IP.
  • Permissions-Policycamera=(), microphone=(self), geolocation=(). Микрофон разрешён только для этого origin (голосовой чат вызывает getUserMedia); при microphone=() браузер отклоняет вызов сразу, даже не спрашивая разрешения.

Фронтенд (модель BFF)

Браузер общается только с маршрутами /api/* своего origin. Токены живут в куках httpOnly и никогда не попадают в клиентский JS. Каждый изменяющий вызов несёт заголовок x-gerege-csrf, который сервер проверяет через checkOrigin — двойная защита от CSRF.

Журнал аудита

С хеш-цепочкой и только на добавление:

chain_hash = SHA-256(prev_hash ‖ canonical-json(entry))

Записи сериализуются через pg_advisory_xact_lock; VerifyChain делает подделку заметной. Чтение — только для админа.

Авторизация (RBAC)

Динамический каталог ролей и разрешений на четырёх уровнях: суперадмин → админ → менеджер → пользователь. Маршруты защищены middleware RequirePermission / RequireAdmin. Суперадмин — единственная роль, управляющая пользователями-администраторами, и он никогда не создаётся через API — только через базу данных или окружение.

Эксплуатационное усиление

В продакшене /metrics и /swagger/doc.json закрыты bearer-токеном (сравнение за постоянное время, 404 при промахе). Логи — структурированные Zap с идентификатором запроса, секреты никогда не логируются.

Дорожная карта ASVS

Уровень Статус
L1 ✅ HTTPS + HSTS, беспарольный вход, параметризованные запросы, заголовки, строгий CORS, валидация ввода, структурированные логи, секреты не в репозитории. ⏳ сканирование контейнеров / govulncheck
L2 ✅ ограничение запросов, ротация refresh, привязка устройства eID (устойчиво к фишингу), таймауты запросов, шифрование интеграционных токенов, аудит с хеш-цепочкой. ⏳ WAF, централизованный SIEM, тест восстановления из бэкапа, план реагирования
L3 ◻ шифрование PII на уровне полей (KMS), mTLS, провенанс SLSA L3, внешний пентест — вне рамок шаблона

Известные пробелы

  • Интерактивный Swagger UI — отдаётся только сырая спецификация по адресу /swagger/doc.json (загрузите её в Swagger Editor или Postman).
  • Полная матрица мер — в backend/docs/SECURITY.md.

Сообщение об уязвимости

Пожалуйста, не открывайте публичный issue. Следуйте процессу из SECURITY.md.