Тема
Авторизация
Материал проходит ревью.
НовичокФундамент ~50 мин
Границы темы
Scope: как backend принимает и применяет решение доступа для конкретного действия, объекта, tenant, поля и контекста, а затем доказывает корректность этого решения.
Не рассматриваем: вход пользователя и проверку credential — это authentication. Здесь principal уже получен на доверенной границе.
Что нужно знать заранее
Статья «Аутентификация и авторизация» разделяет identity, principal, session и access decision. Статья «Принцип наименьших привилегий» задаёт цель минимального scope.
Результаты обучения
После статьи читатель сможет:
- записать policy через subject, action, resource и context;
- разделить управление policy, получение attributes, decision и enforcement;
- выбрать подходящую комбинацию access-control models;
- защитить одиночный объект, список, поле и изменение состояния;
- ограниченно кэшировать решения и отзывать доступ;
- построить matrix tests, которые проверяют deny, а не только happy path.
Основная модель
Авторизация — это вычисление разрешения на действие для entity. NIST SP 800-162 формулирует ABAC через attributes субъекта, объекта, операции и условий среды, оцениваемые относительно policy. Та же четырёхчастная модель полезна независимо от конкретного access-control подхода:
text
decision = policy(subject, action, resource, context)Диаграмма
Правило «admin может всё» является policy, но редко достаточной: оно не ограничивает tenant, опасные actions, separation of duties, время и состояние ресурса.
Основные термины
| Термин | Роль | Пример |
|---|---|---|
| Policy | Набор правил, по которым вычисляется доступ | Refund требует permission и состояние paid |
| Permission | Возможность выполнить action над классом resources | orders:refund |
| Decision | Результат оценки policy | allow, deny, not-applicable |
| Obligation | Действие, обязательное вместе с allow | Mask fields, записать audit, потребовать approval |
| Enforcement point | Компонент, не допускающий выполнение без allow | API middleware/handler boundary |
| Decision point | Компонент, вычисляющий policy | Локальная библиотека или policy service |
| Information point | Доверенный источник attributes | Identity store, resource DB, risk service |
| Administration point | Место изменения и публикации policy | Versioned policy repository |
Архитектура authorization
Логические роли можно реализовать в одном процессе или разных сервисах, но их ответственность должна оставаться различимой.
Диаграмма
- Administration отвечает за review, version, rollout и rollback policy.
- Information отвечает за происхождение и свежесть attributes.
- Decision не должен самовольно выполнять business action.
- Enforcement не должен трактовать отсутствие ответа как allow без явной модели.
End-to-end сценарий: support читает заказ
Требование:
text
Support-инженер может читать заказ только назначенного tenant,
только при активном support case и без полных платёжных реквизитов.Входы decision:
yaml
subject:
id: usr_support_7
roles: [support]
assigned_tenants: [tenant_42]
action: order.read
resource:
id: ord_123
tenant_id: tenant_42
owner_id: usr_customer_9
classification: customer-confidential
context:
support_case: case_88
case_status: active
authentication_age: 12m
policy_version: orders-authz-v17Результат:
yaml
decision: allow
reason: assigned_support_with_active_case
obligations:
- mask: payment_details
- audit: support_order_read
- expires_with: case_88Allow не означает возврат всей database row: field-level obligation ограничивает representation.
Модели доступа
Один продукт часто комбинирует модели.
| Модель | Основа решения | Сильная сторона | Типичный предел |
|---|---|---|---|
| ACL | Список subjects/permissions у resource | Простое sharing конкретного объекта | Сложный review на большом масштабе |
| RBAC | Permissions сгруппированы по roles | Управляемость стабильных job functions | Role explosion и слабый resource context |
| ABAC | Attributes subject/object/action/environment | Гибкие контекстные правила | Качество, provenance и сложность attributes |
| ReBAC | Relationships между entities | Естественно для owner, team, folder graph | Стоимость graph traversal и consistency |
Пример комбинации:
text
role=editor # RBAC: базовая функция
resource.tenant in subject.tenants # ABAC: tenant boundary
subject member_of resource.team # ReBAC: relationship
resource ACL grants comment # ACL: точечное sharingObject-, collection- и field-level enforcement
Конкретный объект
Проверка должна использовать attributes загруженного ресурса:
sql
SELECT id, tenant_id, owner_id, status
FROM orders
WHERE id = $1;После загрузки policy сравнивает principal.tenant_id и order.tenant_id. Знание непредсказуемого ID не является разрешением.
Коллекция
Нельзя загрузить все заказы и отфильтровать запрещённые после pagination. Scope должен войти в запрос:
sql
SELECT id, status, total
FROM orders
WHERE tenant_id = $1
AND owner_id = $2
ORDER BY created_at DESC
LIMIT $3;Иначе возникают утечки через count, pagination, timing, export и memory pressure.
Поля
Один и тот же объект имеет поля разной чувствительности:
| Viewer | Допустимые поля |
|---|---|
| Владелец | Заказ и маскированные payment details |
| Support с case | Заказ без secret/payment fields |
| Финансовый reviewer | Сумма, provider IDs, audit data |
| Anonymous | Ничего |
Сериализация из одной общей entity без projection легко раскрывает новое поле после schema evolution.
Действие и переход состояния
orders:write слишком широко. Разделяйте cancel, refund, change_address и approve_refund; каждое действие имеет собственные preconditions и impact.
Что происходит под капотом
Authorization имеет временную семантику:
Диаграмма
Между decision и action resource может измениться. Для high-impact операции policy должна быть связана с транзакцией, version check или atomic state transition. Иначе появляется time-of-check/time-of-use race.
Deny by default и unknown states
Политика должна различать:
| Состояние | Безопасное поведение |
|---|---|
| Явное allow | Выполнить только заявленные obligations |
| Явное deny | Не выполнять действие, записать reason |
| Нет подходящего правила | Deny by default |
| Attribute отсутствует | Deny или отдельный безопасный fallback по policy |
| Decision service timeout | Bounded fail-closed для sensitive action |
| Policy version неизвестна | Не использовать случайный local default |
OWASP рекомендует deny by default и проверку permission на каждом запросе. Это защищает новый endpoint и неизвестное состояние от неявного allow.
Кэширование и отзыв
Полный cache key включает как минимум:
text
subject version + action + resource id/version + context class + policy versionОшибка cache[role + action] игнорирует tenant, resource state и relationship.
Для cache определите:
- максимальный TTL по impact действия;
- invalidation при revoke роли, membership и relationship;
- rollout новой policy version;
- поведение при недоступности attribute source;
- метрику stale decision и способ emergency revoke.
Критичные actions могут требовать online decision, даже если чтение использует короткий cache.
Минимальный воспроизводимый пример
Создайте decision table до реализации:
| Case | Subject | Action | Resource/context | Expected |
|---|---|---|---|---|
| 1 | Owner tenant 42 | order.read | Свой order tenant 42 | Allow |
| 2 | Owner tenant 42 | order.read | Чужой order tenant 42 | Deny |
| 3 | Owner tenant 42 | order.read | Order tenant 99 | Deny |
| 4 | Support tenant 42 | order.read | Active case tenant 42 | Allow + mask + audit |
| 5 | Support tenant 42 | order.read | Closed case | Deny |
| 6 | Finance reviewer | refund.approve | Собственный refund request | Deny: separation of duties |
| 7 | Unknown role | Любое | Любой resource | Deny |
| 8 | Known role | Unknown action | Любой resource | Deny |
| 9 | Revoked membership | order.read | Cached previous allow | Deny after bounded invalidation |
Ожидаемый результат
Каждое allow объяснимо конкретным правилом; пропущенные attributes и неизвестные actions дают deny; obligations проверяются так же, как allow/deny.
Property checks
Кроме примеров сформулируйте свойства:
text
Для любого subject: если subject.tenant != resource.tenant, decision != allow.
Для любого refund: requester_id == approver_id => deny.
Для любого support allow: case_status == active и присутствует mask obligation.Property-based или генеративные tests помогают найти комбинации, не попавшие в ручную таблицу.
Audit и объяснимость
Decision evidence должно отвечать:
- кто запросил действие;
- какое action и над каким resource;
- какие версии identity/resource/policy участвовали;
- каков outcome и reason code;
- какие obligations применены;
- выполнился ли business action;
- какой request/trace связывает события.
Не записывайте raw tokens, passwords и полный sensitive resource. Audit защищается от несанкционированного чтения и незаметной подмены.
Trade-offs
| Решение | Выигрыш | Цена или риск |
|---|---|---|
| Central PDP | Единая policy и rollout | Network latency и availability dependency |
| Embedded PDP | Низкая latency | Version drift между сервисами |
| RBAC | Простое назначение и review | Role explosion и недостаток context |
| ABAC/ReBAC | Точные динамические решения | Freshness, provenance и сложность policy |
| Decision cache | Availability и latency | Stale permissions и сложная invalidation |
| DB-enforced tenant scope | Дополнительная граница | Контекст identity в соединении и migration complexity |
Failure modes и типичные ошибки
- Allow по умолчанию. Новый action доступен до появления deny rule.
- Проверка только endpoint. Object ID и tenant не участвуют в decision.
- Фильтрация после pagination. Collection metadata и строки уже утекли.
- Role explosion. Для каждой комбинации tenant/context создаётся новая роль.
- Недоверенные attributes. Клиент присылает
tenant_idилиis_admin. - Stale cache. Revoke не влияет на ранее вычисленный allow.
- TOCTOU. Resource state меняется между decision и update.
- Policy drift. Сервисы используют разные версии без наблюдаемого rollout.
- Obligations игнорируются. PDP вернул mask, но serializer отдал полную entity.
- Нет negative testing. Проверены только разрешённые роли.
Практическое задание
Задача: спроектируйте authorization для shared-документа или заказа.
Подготовьте:
- actions вместо общего
write; - subject/resource/context attributes с provenance;
- комбинацию ACL/RBAC/ABAC/ReBAC и обоснование;
- object, collection и field enforcement;
- decision table минимум из 12 cases;
- три properties;
- cache/revocation strategy;
- audit schema и failure behavior PDP/PIP.
Критерии готовности: unknown и missing states дают deny; cross-tenant allow невозможен; obligations тестируются; policy version видна в logs и может быть откачена.
Подсказка
Начните с business actions и отношений, а не с ролей. Роль удобно добавить позже как группу permissions, но трудно извлечь точные правила из уже раздутой role hierarchy.
Проверка знаний
ИНТЕРАКТИВНАЯ ПРОВЕРКА
Проверка знаний
0 / 4
01Какое правило точнее описывает доступ support-инженера к заказу?
02Какие уровни нужно защищать отдельно?
03Authorization decision можно кэшировать бессрочно, если principal уже аутентифицирован.
04Восстановите путь authorization request.
- Enforcement применяет allow/deny и obligations
- Получить доверенные attributes subject/resource/context
- Сформировать subject, action и resource
- Policy engine вычисляет решение и reason
Самопроверка
- Почему role — только один вход authorization decision?
- Чем collection-level enforcement отличается от object-level?
- Какие поля нужны в decision cache key?
- Как обнаружить TOCTOU между policy и update?
- Что должно произойти при неизвестной policy version?
Ответы и критерии
- Role не описывает resource, tenant, relationships, environment и state.
- Object check защищает один resource; collection scope должен ограничить сам query, count, pagination и export до получения данных.
- Версии subject, resource и policy, action, resource identity и значимый context.
- Связать decision с resource version/transaction и проверить конкурентное изменение негативным тестом.
- Sensitive action не выполняется; система создаёт наблюдаемый deny/degraded outcome, а не выбирает неявный default.
Краткое резюме
- Authorization вычисляет policy над subject, action, resource и context.
- Administration, attributes, decision и enforcement — разные ответственности.
- RBAC, ABAC, ACL и relationships можно безопасно комбинировать.
- Защита нужна для функций, объектов, коллекций, полей и state transitions.
- Cache, revocation, policy rollout и audit являются частью correctness.
Следующие шаги
Следующие статьи разбирают RBAC, ABAC, ACL, DAC, MAC и PBAC по отдельности. Начните с RBAC как модели управляемого группирования permissions, сохраняя resource/context checks из этой статьи.
Источники
- NIST SP 800-162 Update 2 — определение ABAC через subject, object, operations, environment и policy.
- NIST RBAC Project — модель users, roles, permissions, operations, objects и ограничения; страница помечена NIST как архивная.
- OWASP Authorization Cheat Sheet — deny by default, проверка каждого запроса, object access, logging и tests.
- NIST SP 800-53 Rev. 5 — семейство Access Control и связанные operational controls.