Skip to main content
Эта страница — адрес для вопросов, которые security review задаёт первыми.
Это фактическое описание софта, а не юридическая консультация и не сертификат соответствия. Какие из этих фактов значимы для вашего регулятора и что с ними делать — решение ваше и вашего юриста.

Кто чем владеет

Veriqa поставляется как код, который вы запускаете у себя. В self-hosted-модели это и есть весь ответ на вопрос «куда уходят данные»:
  • Контроллер — вы. База, ключевой материал и логи находятся на вашей инфраструктуре, под вашими строками подключения. Ничего не разворачивается за вас.
  • Veriqa (вендор) не контроллер и не процессор данных ваших пользователей. Вендору Veriqa не передаётся ничего: продукт не звонит домой, не шлёт телеметрию и не имеет вендорского эндпоинта в принципе. Единственные исходящие адреса в коде — API мессенджеров, которые настроили вы, и SMTP-сервер, на который вы его направили (см. Что уходит за периметр).
  • Провайдеры мессенджеров — ваши контрагенты, а не вендора Veriqa. Telegram, MAX и WhatsApp Cloud API видят сообщения, которые вы отправляете через собственные боты. Отношения с каждым из них у вас прямые.

Инвентарь персональных данных

Всё, чего касается поставляемый продукт, — и ничего сверх того. Чего нет в списке: тела сообщений из канала (адаптер читает то, что нужно для опознания отправителя и подтверждения, и не сохраняет остального) и любой долгоживущий профиль пользователя сверх собранных claims выше. Справочника пользователей продукт не поставляет — см. Идентичности каналов.

Умолчания сбора

Это включено «из коробки». Ни один пункт не требует вашего действия, чтобы начать; каждый требует действия, чтобы прекратить. Две оговорки, которые важнее самих флагов. Геолокация включена по умолчанию, но по умолчанию бездействует. Для поиска нужны сателлитный пакет Veriqa.Core.AuthServer.MaxMind и локальная база .mmdb, а базовые пакеты не несут ни того, ни другого. Без них провайдер объявляет себя недоступным, и гео-поля остаются пустыми — то есть штатная установка местоположения не собирает, хотя флаг говорит true. Сбор начинается ровно с добавлением базы. IP собирается, но никогда не показывается и не логируется. Он попадает в снапшот внутри транзакции и дальше не идёт: сообщение подтверждения называет только приложение, браузер, ОС и регион, а диагностическая запись о недоверенной конфигурации проксирования фиксирует код результата, а не адрес. Выключается всё это одной секцией:
appsettings.json
При Enabled: false снапшот не строится, а сообщение подтверждения просто не несёт строки контекста. Можно и сузить, сохранив контекст: убрать region из DisplayFields или поставить CollectIpAddress: false (тогда отпадёт и геолокация — искать будет не по чему). Подробности и сужение на уровне приложения — в Контексте инициатора.

Где это хранится

Идентичности каналов: по умолчанию не хранится ничего

Порт, который сохранял бы идентичность канала — id пользователя, телефон, email, отображаемое имя, upsert’ом, без TTL и без удаления, — это IChannelIdentityRepository, и Veriqa не поставляет его реализации и не регистрирует ни одной. Вход работает и без неё: разрешённая идентичность едет вместе с транзакцией и исчезает вместе с ней. Хранить эти данные бессрочно — действие, которое вы совершаете осознанно, зарегистрировав свою реализацию; см. Хранилища.

Сроки хранения

Итог: хранилище транзакций опустошает себя примерно за пятнадцать минут после входа, и единственное хранилище Veriqa, где что-то живёт днями, — журнал аудита. Всё, у чего срок жизни бессрочный, добавили вы: репозиторий идентичностей канала, хранилище собранных claims или токены со сроком, который выбрали вы.
Базу OpenIddict чистит сам auth-сервер. Фоновая задача раз в TokenPruneIntervalSeconds (1 ч) удаляет записи токенов и авторизаций, которые уже недействительны (истекли или отозваны) и созданы раньше, чем Veriqa:OpenIddict:Server:TokenPruneThresholdSeconds назад (по умолчанию 24 ч), — при любом провайдере хранилища. Действующие записи не удаляются. Пока запись не вычищена, её payload — для клиентов с avatar вместе с изображением аватара — лежит в базе, поэтому меньший порог сокращает срок хранения этих данных.

Аудит выключен, пока вы не попросите дважды

Два независимых переключателя, и нужны оба:
  1. Сателлит opt-in — хост, который не вызвал AddVeriqaAuditTrail, журнала не имеет вовсе.
  2. Veriqa:Logging:Mode поставляется как System, а записи пишутся только в режиме Audit. Disabled и System для приёмника — одно и то же: не писать.
Ретенция, когда записи появились, третьим переключателем не является: проход регистрируется автоматически для любого встроенного приёмника и удаляет всё старше RetentionDays. ConfigureRetention лишь настраивает частоту прохода и размер батча — он не «включает» ретенцию, и его отсутствие не оставляет записи без срока. Ретенция в ноль и меньше отвергается на старте, а не читается как «не хранить ничего». Единственный случай, когда не подметает ничто, — ваш собственный приёмник, поданный через UseSink<TSink>(). Записи тогда живут в вашем хранилище, встроенный проход не регистрируется, и хост говорит об этом на старте. Границу такому хранилищу ставите вы.
appsettings.json

Что на самом деле лежит в записи аудита

Закрытый набор атрибутов, зафиксированный схемой, — по колонке на атрибут, без произвольного payload: момент, актор, код действия, объект (id транзакции), исход и код причины, плюс тип транзакции, тип канала, correlation id, тенант, client_id, локаль и таймзона интерфейса, собственные безопасные детали канала и объявленный для него уровень входящей верификации. Актор замаскирован. Для действия, которое пользователь совершил в канале, это {канал}:{маскированный id} — читаемыми остаются не более двух последних символов идентификатора. Немаскированное значение не покидает хранилища транзакций. Ни IP, ни User-Agent, ни геолокация, ни отображаемое имя, ни email в запись аудита не попадают. Контекст инициатора живёт в транзакции и умирает вместе с ней. Единственное исключение, которое можно включить, — параметры подтверждаемой операции: заявленный вид действия и значения его слотов. Это предметные данные вашего приложения и в них может быть что угодно, поэтому по умолчанию их нет, и в запись они копируются только по вашему требованию (Харденинг).

Шифрование

Прикладного шифрования хранимых персональных данных сверх этого одного защищённого поля нет, как нет и собственного управления ключами. Если ваша модель угроз требует шифрования ПД at-rest, это требование закрывается на слое хранения, которым управляете вы — шифрованные тома, TDE, защищённое соединение с базой, — а не настройкой в Veriqa. Секреты — client_secret, токены ботов, учётные данные SMTP — живут в переменных окружения или secret-store, но не в конфигах в репозитории. Пароли в лог не попадают: там, где пароль нужно сравнить, сравнение идёт по SHA-256-хешу.

Ключи

Три вида ключевого материала, три разных дома. Сертификаты подписи и шифрования токенов. В Development используются dev-сертификаты OpenIddict. Вне Development загружаются ваши X.509-сертификаты — путём или base64 (Veriqa:OpenIddict:Server:SigningCertificate* / EncryptionCertificate*), и без них хост не стартует.
Замена сертификата инвалидирует сессии. Конфигурация принимает ровно один сертификат подписи и один сертификат шифрования, поэтому в JWKS один ключ подписи и старый с новым нигде не пересекаются. Токены, подписанные прежним ключом, перестают проходить проверку в момент замены. Планируйте смену ключа как регламентное окно, а не как фоновую ротацию — то же предупреждение есть в харденинге.
Кольцо ключей DataProtection. Приоритет — Redis (Veriqa:DataProtection:RedisConnectionString), затем каталог (Veriqa:DataProtection:KeysDirectory); если не задано ни то, ни другое, ключи живут в памяти и теряются при перезапуске. Для разработки это нормально, везде остальное — нет: после рестарта защищённые ожидания живых транзакций уже не прочитать. Data Protection ротирует свои ключи сам, и значения, записанные прежним ключом, читаются, пока тот в кольце, — так что кольцо на устойчивом хранилище делает ротацию незаметной. Секреты каналов и приложений — токены ботов, webhook secret token, client_secret, учётные данные SMTP. Их ротация — операция на стороне канала и клиента; в Veriqa они не кешируются дольше перечитывания конфигурации.

Что уходит за периметр

Только то, для чего вы настроили канал. На одно подтверждение исходящее сообщение несёт:
  • имя приложения, начавшего вход;
  • браузер, ОС и регион инициатора — там, где они известны и включены к показу;
  • ссылку или кнопки подтверждения и срок действия запроса.
Оно не несёт ни IP-адреса, ни сырого User-Agent, ни профильных данных пользователя, ни того, что ваше приложение заявило о транзакции. Куда именно — зависит от канала: api.telegram.org для Telegram, platform-api.max.ru для MAX, graph.facebook.com для WhatsApp Cloud API и ваш собственный SMTP-сервер для Email. В обратную сторону канал возвращает профиль отправителя — поля из таблицы инвентаря выше. Мессенджер видит содержимое сообщения и получателя, потому что это и означает «доставить сообщение»; канал Email видно ровно столько, сколько видит ваш SMTP-релей. Внешняя шина событий. Если подключить публикатор RabbitMQ, события транзакций покидают процесс, неся только безопасную атрибуцию — в том числе маскированную идентичность канала. Параметры подтверждаемой операции явно исключены из сериализации и на шину не попадают ни при какой настройке аудита.

Логи

Логи приложения — не журнал аудита и не задуманы как доказательство. Для этой страницы важно, чего в них быть не должно и что с этим делает код: идентификаторы пишутся 16-символьным необратимым отпечатком (старшие байты SHA-256), а не собой, — так оператор по-прежнему сшивает шаги одного входа, а лог при этом не держит идентичности. Токены, секреты и IP инициатора не логируются вовсе. Это поставляемое поведение собственных лог-записей Veriqa. Ваш хост, ваш обратный прокси и request-логирование платформы — вне его: access-лог перед auth-сервером по умолчанию пишет IP клиентов, и границы ему ставятся тем же шагом развёртывания, что настраивает ForwardedHeaders:KnownProxies.

Что остаётся решить вам

Ни у одного пункта нет правильного ответа, который продукт мог бы выбрать за вас.
  • Держать ли контекст инициатора вообще и добавлять ли базу GeoIP.
  • Включать ли аудит, с каким сроком хранения и должны ли записи нести параметры подтверждаемых операций.
  • Хранить ли идентичности каналов — и если да, как они удаляются.
  • Включать ли хранилище собранных claims и с каким сроком хранения.
  • Сколько истёкшие и отозванные записи токенов живут в базе OpenIddict до чистки.
  • Где живёт кольцо ключей DataProtection.
  • Шифрование at-rest, бэкапы и их сроки — на слое хранения.
  • Как исполняется запрос пользователя на удаление по всем вашим хранилищам. Свои строки транзакций Veriqa удаляет по собственному расписанию, а записи аудита — по ретенции; хранилище собранных claims вы чистите по sub (эндпоинтом или вызовом хоста); до всего, что добавили вы, дотягиваетесь вы.

Дальше

Харденинг перед продом

Чек-лист перед выходом в прод.

Хранилища

Какое хранилище что держит и как каждое подключается.

Известные ограничения

Чего продукт не делает.