Глава 21. Почему ALLOW ещё не означает доступ к данным
21.1. Логический объект и физические данные
Пусть система разрешила:
User A → READ → Document X
Это решение относится к логическому объекту.
Но где находится Document X физически?
Он может быть представлен:
documents
document_versions
document_attributes
document_permissions
document_content
и другими структурами.
Поэтому между:
ALLOW(Object)
и:
SELECT rows
существует архитектурная граница.
21.2. Один объект может соответствовать нескольким строкам
Например:
Document X
│
├── metadata row
├── version row
├── attribute rows
└── content row
Разрешение на объект не объясняет автоматически, какие из этих строк должны быть доступны.
Для каждой физической таблицы может существовать собственное правило.
Получается:
Object authorization
↓
Data-specific enforcement
↓
Allowed physical rows
21.3. Почему проверки только в приложении недостаточно
Представим код:
if hasObjectPermission(user, document):
return repository.findAllRows(document)
Если репозиторий или другой путь к базе данных способен вернуть лишние строки, сама проверка объекта не защищает данные.
Особенно опасны массовые запросы:
SELECT *
FROM documents
Здесь приложение может вообще не проверять каждый объект отдельно.
Нужен механизм, который ограничивает физический результат самого запроса.
21.4. Row-Level Security
Для этого в реляционных базах данных может использоваться RLS (Row-Level Security, безопасность на уровне строк).
RLS позволяет определить, какие строки таблицы доступны конкретному запросу.
Это принципиально другой уровень модели.
Авторизация отвечает:
Может ли субъект выполнить действие над объектом?
RLS отвечает:
Какие физические строки должен увидеть этот запрос?
Поэтому:
Authorization model
↓
Effective authorization
↓
RLS
↓
Physical rows
RLS не заменяет модель авторизации.
21.5. RLS не является ReBAC
Это различие особенно важно.
ReBAC определяет доступ через отношения:
Subject
↓
Relationships
↓
Object
RLS ограничивает физические строки:
Query
↓
Database policy
↓
Rows
Поэтому нельзя сказать:
RLS — это реализация ReBAC.
Это разные уровни.
ReBAC может быть частью модели авторизации.
RLS может быть механизмом физического применения результата этой модели.
21.6. Почему ALLOW не должен отключать RLS
Даже если приложение уже получило:
ALLOW
это не должно автоматически означать:
RLS bypass
Иначе один ошибочный запрос способен получить больше данных, чем разрешено моделью.
Поэтому безопаснее рассматривать границы последовательно:
Object authorization
↓
RLS / data enforcement
↓
Physical rows
Каждый уровень решает свою задачу.
21.7. Разные таблицы — разные границы
Не каждая таблица обязана иметь одинаковую политику.
Например:
objects
→ object-level policy
object_attributes
→ attribute-level policy
object_content
→ content-level policy
audit_log
→ audit-specific policy
Физическая структура данных может иметь собственные ограничения.
Это ещё одна причина не считать:
ALLOW(object)
универсальным разрешением на всё, что технически связано с объектом.
21.8. В Guardian
Архитектура выглядит так:
Security source facts
↓
Security projections
↓
effective_user_permission
object_scope
↓
has_object_permission
↓
RLS
↓
Physical rows
has_object_permission() отвечает за логическую авторизацию объекта.
RLS остаётся отдельной границей применения к физическим данным.
21.9. Главный вывод
Безопасность данных требует двух разных вопросов:
1. Можно ли субъекту работать с объектом?
2. Какие физические данные должен увидеть этот запрос?
Первый вопрос относится к авторизации.
Второй — к применению этой авторизации к данным.
Поэтому:
ALLOW(Object) ≠ unrestricted data access
Это различие становится особенно важным, когда система выполняет массовые запросы или когда один логический объект представлен несколькими физическими структурами.