Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Глава 25. Один запрос от начала до конца

До этого момента модель доступа рассматривалась по частям.

Мы отдельно говорили об объекте, субъекте, отношениях, областях, публикациях, разрешениях, проекциях и физической защите данных.

Теперь соберём их в одну последовательность.

Рассмотрим один обычный запрос:

Subject S
    хочет выполнить
Action A
    над
Object O

На первый взгляд достаточно ответить:

ALLOW

Но реальная система должна пройти значительно больший путь:

Request
   ↓
Subject
   ↓
Object
   ↓
Relevant facts
   ↓
Context
   ↓
Access grounds
   ↓
Effective permission
   ↓
Object authorization
   ↓
Data enforcement
   ↓
Physical data

Каждый этап отвечает на свой вопрос.

Именно разделение этих вопросов позволяет сложной модели оставаться объяснимой.

25.1 Сначала определяется сам запрос

Любое решение о доступе начинается не с роли и не с таблицы разрешений.

Оно начинается с конкретного действия.

Есть:

Subject = S
Action  = READ
Object  = O

То есть система должна понять:

кто действует, что он хочет сделать и над чем именно.

Это кажется очевидным, но именно здесь исчезает слишком простая модель:

User → Permission

Пользователь не получает абстрактное право «читать».

Он выполняет конкретное действие над конкретным объектом.

Поэтому два запроса одного пользователя могут иметь разные результаты:

READ(Object A)
READ(Object B)

даже если субъект один и тот же.

Точно так же один объект может давать разные результаты для разных действий:

READ(Object A)
UPDATE(Object A)
CLOSE(Object A)

Следовательно, запрос является точкой, относительно которой строится весь дальнейший контекст.

25.2 Затем определяется субъект и объект

После фиксации действия система должна определить две стороны отношения:

Subject
Object

Субъект — тот, от чьего имени принимается решение.

Объект — предмет действия.

Важно не смешивать субъекта с механизмом аутентификации.

Например, HTTP-запрос может пройти через:

client
   ↓
API
   ↓
service
   ↓
database

Но это не означает, что каждый из этих компонентов является субъектом бизнес-действия.

Система должна сохранить идентичность того субъекта, от имени которого выполняется операция.

После этого определяется объект.

В простом случае он известен непосредственно из запроса:

GET /objects/123

В более сложном запросе объект может определяться через набор условий или вообще отсутствовать как единственный экземпляр.

Например:

SELECT *
FROM objects
WHERE project_id = :project;

Тогда запрос потенциально затрагивает множество объектов.

Это уже влияет на дальнейшую модель проверки.

25.3 Из исходных данных выбираются релевантные факты

После определения Subject, Action и Object система должна понять, какие факты имеют отношение к этому решению.

Например:

Subject S
 ├── role R
 ├── member of Group G
 └── assigned to Project P

Object O
 ├── owned by S2
 ├── published in Project P
 └── related to Group G2

Но весь набор фактов системы здесь не нужен.

Нас интересуют только те, которые могут изменить результат конкретного решения.

Это и есть переход к контексту:

All system facts
       │
       ▼
Relevant facts
       │
       ▼
Context(S, A, O)

Контекст не обязан существовать как одна физическая сущность.

Это логическое множество фактов и отношений, необходимых для данного решения.

25.4 Из контекста определяются основания доступа

Следующий вопрос:

почему этот субъект вообще может получить доступ к этому объекту?

Например, основанием может быть:

ownership
membership
role
publication
delegation

Но наличие отношения ещё не означает наличие права.

Например:

S → member of P

говорит, что субъект связан с проектом.

Но из этого самого по себе ещё не следует:

S → READ → O

Нужны правила, которые определяют значение этого отношения.

Поэтому следующий переход выглядит так:

Relevant facts
      ↓
Access grounds
      ↓
Rules

Именно здесь модель превращает факты в основания, а основания — в потенциальные разрешения.

25.5 Формируется эффективное разрешение

Теперь система может определить, какие разрешения действительно применимы.

Пусть существуют два основания:

Role R
    → READ, UPDATE

Publication P
    → makes Object visible

Они выполняют разные функции.

Роль может дать разрешение на действие.

Публикация может сделать объект доступным в соответствующей области.

Поэтому нельзя просто сложить все отношения в один список.

Система должна применить правила композиции.

Результатом становится:

EffectivePermission(S, O)

Причём результат может зависеть от области:

READ @ Project P
UPDATE @ Project P

а не просто:

READ
UPDATE

Это принципиально.

Право без области может быть недостаточно определённым для объектной модели.

Поэтому эффективное разрешение является производным фактом:

Source facts
     +
Rules
     ↓
Effective permission

25.6 Выполняется проверка объектного действия

Теперь можно задать конкретный вопрос:

Can(S, READ, O)?

Проверка использует подготовленную модель.

В ней могут участвовать:

  • эффективные разрешения субъекта;

  • область их действия;

  • публикация объекта;

  • другие объектные ограничения;

  • специальное основание, например владение.

Результатом становится:

ALLOW

или:

DENY

Но здесь важно не остановиться.

ALLOW означает:

модель авторизации разрешила субъекту выполнить это действие над этим логическим объектом.

Он ещё не означает:

база данных обязана вернуть субъекту любые строки, связанные с этим объектом.

Это различие мы установили в предыдущих главах.

Поэтому после объектной авторизации путь продолжается.

25.7 Запрос переходит к физическим данным

Теперь приложение должно получить или изменить реальные данные.

Например:

SELECT *
FROM document
WHERE id = :id;

Или:

SELECT *
FROM document_attribute
WHERE object_id = :id;

Здесь вступает в действие физическая модель безопасности.

База данных должна понимать, какие строки допустимы для текущего субъекта.

Поэтому появляется ещё одна проверка:

Object authorization
        +
Data enforcement
        ↓
Actual rows

Если используется RLS, политика базы данных применяется непосредственно к обращению к таблице.

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

В результате конечный ответ системы определяется не только тем, что модель сказала ALLOW, но и тем, какие физические строки реально прошли ограничения данных.

25.8 Один запрос в собранной модели

Теперь можно посмотреть на весь путь целиком.

                 REQUEST
                    │
                    ▼
          Subject / Action / Object
                    │
                    ▼
             Relevant facts
                    │
                    ▼
                 Context
                    │
                    ▼
            Access grounds
                    │
                    ▼
                  Rules
                    │
                    ▼
        Effective permission
                    │
                    ▼
         Object authorization
                    │
                  ALLOW
                    │
                    ▼
          Data enforcement
                    │
                    ▼
             Physical rows

Это не обязательно означает, что в системе существует столько последовательных вызовов.

Некоторые этапы могут быть заранее вычислены.

Некоторые — объединены.

Некоторые — реализованы непосредственно в базе данных.

Но логически эти вопросы должны быть различимы.

Это позволяет понять, где искать ошибку.

Если пользователь неожиданно не видит объект, проблема может находиться в:

facts
relations
publication
projection
effective permission

Если объектная проверка возвращает ALLOW, но SQL не возвращает строку, искать проблему нужно уже ниже:

object → physical data mapping
RLS
database security context

Разделение уровней делает такую диагностику возможной.

25.9 Почему нельзя выполнять весь путь заново для каждого запроса

Сквозной алгоритм может показаться дорогим.

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

Поэтому мы ранее разделили два времени.

Время изменения модели:

Source fact changes
       ↓
Security projections update

Время запроса:

Request
   ↓
read prepared security state
   ↓
check
   ↓
query data

Это одно из главных архитектурных следствий всей модели.

Мы не пытаемся заранее вычислить все возможные:

Subject × Action × Object

Но заранее строим те производные факты, которые можно переиспользовать.

Таким образом, сложность переносится из каждого запроса в процесс изменения модели безопасности.

25.10 Что происходит при изменении одного отношения

Предположим, субъект больше не является членом группы.

На уровне предметной модели изменился один факт:

S → Group G

Но запросы, которые раньше разрешались через эту связь, могут быть многочисленными.

Поэтому изменение проходит обратный путь:

Source fact changed
       ↓
Affected security facts
       ↓
Projections
       ↓
Effective permissions
       ↓
Future authorization decisions
       ↓
Data access

Важно, что сам объект при этом может вообще не измениться.

Меняется отношение вокруг него.

Но результат запроса:

Can(S, READ, O)

может измениться.

Это ещё раз показывает, почему доступ нельзя считать простым свойством объекта.

25.11 Что происходит при изменении объекта

Теперь рассмотрим обратный случай.

Объект меняет публикацию:

Object O
   was published in P1
   becomes published in P2

Сам пользователь может не измениться.

Его роль тоже может не измениться.

Но изменяется объектная сторона отношения.

Поэтому меняется контекст:

Object facts
     ↓
Object security projection
     ↓
Applicable permissions
     ↓
Authorization result

Следовательно, изменение доступа может быть вызвано изменением:

  • субъекта;

  • отношения;

  • роли;

  • области;

  • публикации;

  • объекта;

  • правила.

Это и есть причина, по которой security model должна рассматриваться как отдельная производная модель системы.

25.12 Один запрос — несколько уровней ответственности

Теперь можно сформулировать границы ответственности.

Доменная модель отвечает за то, какие объекты и отношения существуют.

Модель безопасности определяет, какие из этих фактов имеют значение для доступа и как они интерпретируются.

Проекционный слой подготавливает производные security facts.

Авторизация определяет допустимость конкретного действия.

Механизм защиты данных ограничивает фактически доступные физические данные.

Это можно представить так:

Domain
   ↓
Security model
   ↓
Projection
   ↓
Authorization
   ↓
Data enforcement

Ни один уровень не должен незаметно брать на себя ответственность всех остальных.

Иначе система снова превращается в один большой механизм с неясными границами.

25.13 Главный вывод

Один запрос к защищённым данным — это не одна проверка.

Это прохождение через несколько логически различных вопросов:

Кто действует?
        ↓
Что он хочет сделать?
        ↓
Над каким объектом?
        ↓
Какие факты здесь релевантны?
        ↓
Какие отношения являются основаниями доступа?
        ↓
Как из них получается эффективное разрешение?
        ↓
Разрешено ли конкретное действие?
        ↓
Какие физические данные действительно доступны?

В компактном виде:

Subject
   +
Action
   +
Object
   ↓
Context
   ↓
Access grounds
   ↓
Effective permission
   ↓
Authorization
   ↓
Data enforcement
   ↓
Physical data

Главное здесь не последовательность вызовов.

Главное — разделение смыслов.

Контекст не является разрешением.

Разрешение не является решением.

Решение не является доступом к физическим данным.

А физическая строка не является самим логическим объектом.

Когда эти уровни разделены, сложная модель перестаёт выглядеть как набор исключений.

Она становится последовательным преобразованием:

из фактов и отношений — в контекст, из контекста — в разрешение, из разрешения — в ограниченный доступ к данным.

Но до сих пор мы рассматривали в основном чтение уже построенной модели.

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

Именно изменение отношений и является предметом следующей главы.