Что такое ABAC? Управление доступом на основе атрибутов с примерами
Что такое ABAC?
Управление доступом на основе атрибутов (ABAC) разрешает или запрещает запрос, оценивая атрибуты относительно правил, вместо того чтобы искать, кто такой пользователь или какая у него роль. NIST, опубликовавший эталонное определение в SP 800-162, группирует входные данные в четыре вида:
| Атрибуты | Примеры |
|---|---|
| Субъект (пользователь или сервис) | отдел, уровень допуска, тип занятости, возраст |
| Объект (ресурс) | владелец, отдел, классификация, статус |
| Действие | чтение, редактирование, утверждение, удаление |
| Окружение | время суток, IP-адрес или сеть, устройство, местоположение |
Правило — это условие над этими атрибутами, например: «пользователь может читать документ, если он находится в том же отделе, что и документ, в рабочее время». Поскольку правило ссылается на атрибуты, а не на именованных пользователей или роли, новые пользователи и новые документы покрываются автоматически, без добавления новых правил.
Casbin делает ABAC простым: вы передаете структуры или объекты в Enforce() и обращаетесь к их полям в матчер. Полные примеры приложений приведены в руководствах по ABAC для Go, Node.js с Express и Python с Flask.
ABAC против RBAC
RBAC принимает решения на основе ролей пользователя: «редакторы могут редактировать документы». ABAC принимает решения на основе атрибутов: «владелец может редактировать документ». Роли легко аудировать, так как можно перечислить, что разрешает роль и кто её имеет; атрибуты выражают правила для конкретных записей и контекста, такие как владение, отдел или время, которые нельзя выразить только ролями без создания отдельной роли для каждой записи. Большинство приложений комбинируют их: роли определяют, какие функции доступны пользователю, а условия по атрибутам сужают доступ до тех записей, которые он может трогать. Выбор модели контроля доступа сравнивает ACL, RBAC, ABAC и ReBAC на одном примере и показывает, как объединить RBAC с ABAC в одной модели Casbin.
Сильные и слабые стороны
- Хорошо подходит для: владения («только свои»), контекста (рабочее время, офисная сеть) и данных, несущих собственные метки (отдел, регион, чувствительность). Одно правило может заменить множество назначений ролей.
- Плохо подходит для: аудита. На вопрос «Кто может читать этот документ?» нет прямого ответа; нужно проверить правило для каждого пользователя. Правила также требуют наличия атрибутов под рукой, поэтому приложение обычно загружает запись перед проверкой.
Минимальный пример:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == r.obj.Owner
Таким образом, r.obj должен быть объектом с полем Owner; Casbin читает его через рефлексию. В Go вы можете определить:
type testResource struct {
Name string
Owner string
}
Вы также можете передавать JSON-строки; включите обработку JSON, и Casbin разберёт их:
e, _ := NewEnforcer("examples/abac_model.conf")
e.EnableAcceptJsonRequest(true)
data1Json := `{ "Name": "data1", "Owner": "bob"}`
ok, err := e.Enforce("alice", data1Json, "read")
if err != nil {
// Handle JSON parsing errors
fmt.Printf("Enforcement failed: %v\n", err)
return
}
При включении любой параметр, начинающийся с { или [, интерпретируется как JSON. Неверный JSON вызывает понятную ошибку; другие строки остаются как есть.
// Valid JSON - automatically parsed
validJSON := `{"Name": "alice", "Age": 25}`
ok, err := e.Enforce(validJSON, "data1", "read") // Works correctly
// Invalid JSON - returns descriptive error
invalidJSON := `{"Name": "alice",}` // Trailing comma is invalid in JSON
ok, err := e.Enforce(invalidJSON, "data1", "read")
// Returns: "failed to parse JSON parameter at index 0: ..."
// Plain string - no parsing attempted
plainString := "alice"
ok, err := e.Enforce(plainString, "data1", "read") // Treated as plain string
Включение поддержки JSON-параметров вносит накладные расходы на производительность примерно в 1.1–1.5 раза.
Атрибуты окружения
Запрос может содержать больше, чем просто sub, obj и act. Добавьте поле для окружения и передайте его в Enforce(), как любой другой объект. Эта модель позволяет владельцу редактировать свой документ в любое время, а сотрудникам того же отдела — читать его с 9:00 до 18:00:
[request_definition]
r = sub, obj, act, env
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub.Name == r.obj.Owner || (r.act == "read" && r.sub.Department == r.obj.Department && r.env.Hour >= 9 && r.env.Hour < 18)
type User struct{ Name, Department string }
type Doc struct{ Name, Owner, Department string }
type Env struct{ Hour int }
doc := Doc{Name: "design.md", Owner: "alice", Department: "design"}
bob := User{Name: "bob", Department: "design"}
ok, _ := e.Enforce(bob, doc, "read", Env{Hour: 10}) // true
ok, _ = e.Enforce(bob, doc, "read", Env{Hour: 22}) // false: outside business hours
ok, _ = e.Enforce(bob, doc, "edit", Env{Hour: 10}) // false: bob is not the owner
Использование ABAC
- Обращайтесь к атрибутам в матчере (например,
r.sub.Role,r.obj.Owner). - Передавайте экземпляры структур или классов (или JSON) в
Enforce().
Доступ к атрибутам ABAC работает только для элементов запроса (r.sub, r.obj, r.act). Элементы политики, такие как p.sub, не могут использовать ABAC, так как политики не могут хранить определения структур или классов.
Матчеры могут одновременно ссылаться на несколько атрибутов. Пример: m = r.sub.Domain == r.obj.Domain.
Если политики требуют запятых, которые конфликтуют с парсингом CSV, оберните выражение в кавычки. Пример: "keyMatch("bob", r.sub.Role)" предотвращает нежелательное разбиение.
Сложные правила с eval()
Для более сложных условий помещайте выражения в политику и вычисляйте их с помощью eval(), чтобы модель оставалась компактной, а политики — гибкими.
Конфигурация модели с eval():
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub_rule, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = eval(p.sub_rule) && r.obj == p.obj && r.act == p.act
p.sub_rule — это выражение над атрибутами запроса, вычисляемое во время проверки. Пример политики:
p, r.sub.Age > 18, /data1, read
p, r.sub.Age < 60, /data2, write
FAQ
ABAC лучше, чем RBAC? Ни один из них не является лучше в общем смысле. ABAC выражает более тонкие правила; RBAC проще для проверки. Начните с ролей и добавьте условия по атрибутам там, где роли перестают подходить, например, для владения или временных окон.
В чём разница между ABAC и PBAC? ABAC определяет, на чём основаны решения (на атрибутах). PBAC определяет, как управляются правила: как данные политики, оцениваемые во время выполнения. Приведённый выше паттерн eval() относится к обоим: условия по атрибутам, хранящиеся как политика.
ABAC то же самое, что XACML? Нет. XACML — это стандартный язык OASIS для написания политик ABAC. Casbin не использует XACML; правила пишутся в матчере модели или хранятся как строки политики.
Могу ли я попробовать ABAC без написания кода? Да. Выберите пример ABAC в онлайн-редакторе и отредактируйте матчер и запрос.
Comments are powered by giscus and GitHub Discussions. They load from giscus.app and GitHub only after you click the button below.