Если пользователь аналитики видит чужой проект, фильтр в интерфейсе уже не является защитой. Доступ должен ограничиваться на сервере в каждом запросе и, по возможности, на уровне базы или представления.
Ограничьте доступ к проблемному отчёту, сохраните обезличенный пример и проверьте, откуда 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 и экспортов, нужен полный аудит пути авторизации, а не исправление одного экрана.
Итог
Изоляция проектов должна быть системным свойством. Я могу найти обходной путь, закрыть доступ и добавить тесты, которые не позволят следующему отчёту повторить ошибку.