Если пользователь аналитики видит чужой проект, фильтр в интерфейсе уже не является защитой. Доступ должен ограничиваться на сервере в каждом запросе и, по возможности, на уровне базы или представления.

Ограничьте доступ к проблемному отчёту, сохраните обезличенный пример и проверьте, откуда backend получает tenant_id: из проверенной сессии или из параметра клиента.

Что сделать в первую очередь

  • Закройте отчёт или роль, которая раскрывает чужие данные.
  • Зафиксируйте пользователя, проект и запрос.
  • Проверьте другие отчёты с тем же источником.
  • Определите период, в котором ошибка была доступна.

Почему возникает проблема

Межпроектная утечка возникает, когда tenant-фильтр добавляется нецентрализованно или теряется в производном запросе.

  • project_id принимается напрямую из URL.
  • Один запрос отчёта не добавляет tenant_id.
  • Materialized view объединяет данные без признака владельца.
  • Кэш ключуется только параметрами отчёта.
  • Экспорт выполняется с системными правами без повторной проверки.

Пошаговая диагностика

  • Проследите запрос от сессии до финального SQL.
  • Проверьте все join на сохранение tenant_id.
  • Сравните онлайн-отчёт и экспорт.
  • Проверьте кэш двумя тестовыми tenants.
  • Найдите запросы с широкими сервисными credentials.

Как исправить

Защита должна применяться автоматически и не зависеть от того, помнит ли разработчик добавить WHERE.

  • Получайте tenant_id только из авторизованного контекста.
  • Используйте общий query builder или безопасные представления.
  • Добавьте tenant_id в ключи кэша и фоновые задания.
  • Ограничьте сервисную роль и разделите права чтения.
  • Добавьте проверку владельца перед экспортом и скачиванием.

Как проверить результат

  • Пользователь видит только свои проекты во всех форматах.
  • Подмена project_id возвращает отказ.
  • Кэш не переносит результат между tenants.
  • Негативные тесты проходят для отчёта, API и экспорта.

Как не допустить повторения

  • Добавьте автоматический тест tenant isolation.
  • Проводите ревизию новых отчётов.
  • Логируйте доступ к чувствительным выгрузкам.
  • Не используйте общий публичный URL для персональных экспортов.

Чего не стоит делать

  • Не исправляйте проблему только скрытием проекта в UI.
  • Не давайте приложению административную роль базы без необходимости.
  • Не распространяйте скриншоты чужих данных при разборе.

Что подготовить для диагностики

  • ID пользователей и проектов без содержимого отчётов.
  • SQL или код формирования запроса.
  • Схема ролей и tenants.
  • Описание кэша и фоновых экспортов.

Частые вопросы

Достаточно ли row-level security?

RLS сильно помогает, но нужно правильно передавать контекст и отдельно защищать кэш, экспорты и внешние хранилища.

Почему ошибка только в одном отчёте?

У него может быть отдельный SQL, представление или сервисный путь, который обходит общий фильтр.

Когда стоит обратиться за помощью

Если данные доступны через несколько API и экспортов, нужен полный аудит пути авторизации, а не исправление одного экрана.

Итог

Изоляция проектов должна быть системным свойством. Я могу найти обходной путь, закрыть доступ и добавить тесты, которые не позволят следующему отчёту повторить ошибку.