Skip to main content
Это чек-лист того, что команды чаще всего упускают перед выходом в прод. Это не полный гайд по деплою — фокус только на легко пропускаемых пунктах. Состояние галочек хранится локально в браузере; нужна копия — print-to-PDF браузера.
Что продукт собирает, где хранит и сколько держит — инвентарь, умолчания сбора, сроки хранения и что уходит за периметр — вынесено на отдельную страницу: Безопасность и обработка данных. Этот чек-лист — про решения, которые принимаете вы; та страница — про факты, на которых вы их принимаете.

Issuer и сертификаты

  • Стабильный HTTPS issuer, актуальный JWKS, спланированная замена ключей.
Issuer должен быть постоянным HTTPS-адресом — он попадает в iss токенов и в discovery. Клиенты обязаны доверять ключам через discovery / JWKS, а не через зашитую статику: тогда замена ключа не требует правок на их стороне. Вне Development сертификаты подписи и шифрования обязательны в обоих режимах поставки, встроенном и self-hosted, — без них хост не стартует (ключи: справочник конфигурации).
Ротация без простоя не поддерживается. Конфигурация принимает один сертификат подписи и один сертификат шифрования, поэтому JWKS отдаёт один ключ подписи — перекрытия старого и нового нет. Замена сертификата инвалидирует живые токены, подписанные прежним ключом; то же предупреждение — в self-hosted-старте. Планируйте замену ключей как операцию с инвалидацией сессий, а не как фоновую.

Клиентские секреты и хранение

  • client_secret и токены каналов — вне репозитория, через окружение, с шифрованием и ротацией.
Секреты (клиентские client_secret, токены ботов, ключи API каналов) передаются только через переменные окружения / секрет-стор, не через файлы конфигурации и не в гите. Шифруйте at-rest и ротируйте.

OIDC PKCE и state

  • PKCE (S256) обязателен для public-клиентов; валидируйте state и nonce.
Для публичных клиентов PKCE с методом S256 обязателен. state защищает от CSRF на редиректе, nonce привязывает id_token к сессии. Veriqa дополнительно проверяет одноразовый browser-nonce в callback — не отключайте эти проверки.

Redirect URIs

  • Whitelist exact-match; без wildcard в проде; https только (кроме loopback в dev).
Redirect URI сверяется точным совпадением. Wildcard в продакшне запрещён, http допустим только для loopback-адресов (localhost, 127.0.0.1, [::1]) при разработке.

Scopes и claims

  • Минимальный набор scopes; openid обязателен; не запрашивать лишний PII.
Запрашивайте минимум: openid обязателен, остальное — по необходимости. Не просите email, если он не нужен; не храните PII сверх требуемого. /userinfo отдаёт только claims, разрешённые scopes и конфигурацией.

Rate limiting и anti-abuse

  • Лимиты ядра подобраны под трафик каждого маршрута; per-IP-ограничитель стоит на reverse-proxy / WAF.
Ядро ограничивает каждую публичную поверхность одним общим бакетом на маршрут — authorize, token, callback, polling, вебхуки, SignalR, стартовая страница Email, страницы подтверждения (дефолты — в конфигурации). Поверх этого оно считает попытки входа по пользователю (channel identity), чтобы подтверждение нельзя было перебрать, и даёт каждому relying party собственный бюджет на server-to-server входе подтверждения. Общие бакеты подбирайте под суммарный трафик маршрута: они защищают доступность, а не одного посетителя от другого. Чего ядро не делает — не считает ни один лимит по IP клиента и не блокирует адреса. Per-IP-лимит ловит единственное, чего не видят два других ключа, — горизонтальный перебор: много аккаунтов с одного адреса, каждый в пределах своего пользовательского лимита, — и этот слой живёт на краю, который у вас уже есть: limit_req в NGINX, rate-правило WAF, fail2ban по 429 в access-логе. Тем же шагом развёртывания настраивается ForwardedHeaders:KnownProxies (см. self-hosted, шаг 6): край видит реальный адрес клиента, ядро доверяет только тому, что край пробросил. Установка без ограничителя на краю открыта для такого перебора, поэтому поставьте его до выхода в прод.

Ротация refresh-токенов

  • Включить rotation и revocation; реагировать на повторное использование.
Включите ротацию и отзыв refresh-токенов. При повторном использовании (replay) отзывайте всё семейство токенов.

Логирование и аудит

  • Никогда не логировать токены / секреты / PII; включить аудит транзакций.
Токены, секреты и персональные данные в логи не попадают. Включите журнал аудита транзакций — он даёт прослеживаемость входов и подтверждений. Журнал пишется по событиям транзакции — создание, подтверждение, завершение, отказ, истечение — и по security-событиям каналов. Каждая запись фиксирует время, действующее лицо, код события (action), объект и исход (result).
Два известных ограничения журнала — учтите их, планируя отчётность и разбор инцидентов.Выпуск токенов не аудируется. Ни первичный выпуск по authorization code, ни ротация refresh-токена аудит-записи не создают: журнал пишется по событиям транзакции, а выпуск токенов через них не проходит и к транзакции не привязан — тем более ротация, которая случается уже вне её жизненного цикла. Не стройте доказательство выдачи токена на аудит-журнале: выпуск и ротацию контролируют отзыв токена и отзыв всего семейства при replay (см. Ротация refresh-токенов).Исход канальной security-записи неинформативен. У записей, порождённых security-событиями канала, поле исхода одинаково — «отказ», и так для любого кода канала. «Отказ» в такой строке не значит «что-то сломалось»: смысл события несёт код в поле action, а его словарь даёт документация конкретного канала. Фильтруйте и разбирайте такие записи по action, а не по исходу.
Параметры подтверждённой операции — по явному включению. По умолчанию записи транзакции подтверждения не содержат, что именно подтверждали: объявленный вид действия и значения слотов — предметные данные вашего приложения и могут содержать персональные. Если журнал должен отвечать на вопрос «какая операция и с какими параметрами была подтверждена», включите это осознанно:
Program.cs
Включённые параметры копируются в саму запись, а не берутся по ссылке на транзакцию: завершённая транзакция удаляется через минуты, а запись живёт весь срок retention. Их получает каждая аудит-запись такой транзакции — не только запись подтверждения, но и создание, завершение, отказ, истечение: вопрос «какая это была операция» задают и к ним. Из процесса эти параметры не уходят — во внешнюю шину событий они не публикуются.

Уровень проверки входящего события канала

  • InboundVerification объявлен у каждой канальной секции — и объявлен осознанно.
Каждая канальная секция обязана нести InboundVerification: развёртывание с включённым поставляемым каналом без значения не стартует. Стартовая проверка перебирает тот же набор каналов, из которого ядро строит список включённых: все четыре поставляемых канала в нём есть, а канал стороннего адаптера, подключённый одним вызовом AddChannel, — нет, и его секцию проверяете глазами вы. Смотрите не на то, что ключ есть, а на то, что в нём написано: значение обязано соответствовать режиму, в котором канал реально работает (таблица — в Настройке каналов). Расхождение здесь тихое: канал в вебхук-режиме, которому объявили outbound_fetch, стартует молча. none — осознанный выбор, а не умолчание: он означает «подлинность входящего события не проверяется», то есть эндпоинт подтверждения этого канала принимает запрос от кого угодно. Ставьте его, только если действительно приняли этот риск, и заносите такое решение туда, где хранятся остальные решения о рисках.

Доступность каналов

  • Определить поведение при недоступности канала.
Заранее решите, что происходит, если канал недоступен: предложить альтернативный канал или показать понятную ошибку — но не «зависать» в незавершённой транзакции.

Локализация и доступность

  • WCAG 2.2 AA; locale-файлы для языков вашей аудитории.
Страницы входа и подтверждения проектируются под WCAG 2.2 AA. Отдельный хост из Dockerfile поставляет переводы на английский, русский и китайский; во встроенном режиме каталог локалей поставляет ваш хост, и без него страница отображается на английском (см. Локализацию). Формального аудита доступности с публикуемым отчётом не проводилось — если он требуется вашему регламенту, планируйте его на своей стороне.

Версионирование и миграции

  • SemVer SDK; для реляционных хранилищ — миграции, а не авто-создание схемы.
Следуйте SemVer и планируйте апгрейды между minor / major. Реляционные хранилища инициализируйте миграциями (история схемы), а не авто-созданием.

Операционные основы

  • Health-probe, шифрованный канал к БД, secret storage, внешний JS на странице входа выключен.
Health-probe хоста, шифрованное соединение с БД, хранение секретов в секрет-сторе. Внешний JS на странице аутентификации по умолчанию запрещён — включайте только осознанно (см. кастомизацию).

Дальше

OIDC + Veriqa: разбор

Разберитесь, где именно Veriqa встаёт в OIDC-поток.