RBAC и ABAC: как спроектировать роли и права доступа в приложении
Практика3 минРедакция Innovialabs
Коротко
Начните с RBAC — ролей, которые объединяют именованные права, — и добавляйте ABAC-правила только там, где доступ зависит от данных, например «свои сделки» или «сделки своего филиала», проверяя всё на сервере.
Коротко
- RBAC (role-based access control): пользователю назначаются роли, роли — права. «Менеджер может редактировать сделки». Просто понять и проверить.
- ABAC (attribute-based access control): решение принимается по атрибутам пользователя, объекта и контекста. «Менеджер может редактировать сделку, если она из его филиала и не закрыта».
Большинство реальных приложений используют гибрид: RBAC отвечает на вопрос «может ли человек вообще делать такое действие», атрибутные правила — «с какими именно записями».
Сравнение
| RBAC | ABAC | |
|---|---|---|
| На что отвечает | Какие действия разрешает роль? | Можно ли это действие с этим объектом сейчас? |
| Пример в CRM | Менеджер продаж видит сделки | Менеджер видит только сделки своего филиала |
| Сложность настройки | Низкая | Выше: правила нужно продумать и протестировать |
| Аудит | Просто: список ролей и прав | Сложнее: нужно читать правила |
| Типичный риск | Взрыв числа ролей | Правила, которые никто не понимает |
Моделируйте права, а не роли
Самая частая ошибка — проверять роль в коде: if (user.role === "admin"). Когда появляется новая роль, приходится искать все такие проверки. Вместо этого проверяйте права, а роли пусть будут просто их наборами.
CREATE TABLE permissions (
id serial PRIMARY KEY,
code text UNIQUE NOT NULL -- например 'deals.view', 'deals.edit', 'users.manage'
);
CREATE TABLE roles (
id serial PRIMARY KEY,
name text UNIQUE NOT NULL
);
CREATE TABLE role_permissions (
role_id int REFERENCES roles(id),
permission_id int REFERENCES permissions(id),
PRIMARY KEY (role_id, permission_id)
);
CREATE TABLE user_roles (
user_id int REFERENCES users(id),
role_id int REFERENCES roles(id),
PRIMARY KEY (user_id, role_id)
);
Коды прав живут в коде как константы, роли — в базе, и их можно менять в админке без релиза.
Атрибуты — там, где важны данные
Правила области видимости обычно зависят от нескольких атрибутов: владелец, команда, филиал, статус записи. Соберите их в одну функцию-политику на ресурс:
function canEditDeal(user: User, deal: Deal): boolean {
if (!user.permissions.has("deals.edit")) return false;
if (deal.status === "closed") return user.permissions.has("deals.edit_closed");
if (user.permissions.has("deals.edit_any")) return true;
if (deal.ownerId === user.id) return true;
return user.permissions.has("deals.edit_branch") && deal.branchId === user.branchId;
}
Для списков применяйте то же правило как фильтр в запросе к базе, а не загружайте всё и прячьте строки в интерфейсе. Иначе API всё равно отдаст данные чужих филиалов, а счётчики пагинации будут неверными.
Проверки — на сервере
- Интерфейс может скрывать кнопки, но каждый API-эндпоинт сам проверяет права. Запрос можно отправить напрямую, минуя интерфейс.
- Проверяйте доступ к конкретному объекту, а не только к действию. Замена
/deals/42на/deals/43не должна открывать чужую сделку — это классическая уязвимость IDOR (broken object level authorization). - Запрет по умолчанию: новый эндпоинт без политики должен возвращать 403, а не работать для всех.
- Логируйте изменения прав и назначение ролей как события безопасности.
Как избежать взрыва ролей
Взрыв ролей начинается, когда каждое исключение превращается в новую роль: «Менеджер Ташкент», «Менеджер Самарканд», «Менеджер Ташкент без экспорта»…
- Роли описывают должностные функции, а область (филиал, команда, регион) уходит в атрибуты.
- Разрешите несколько ролей на пользователя вместо комбинированных ролей.
- Редкие права выдавайте отдельно, а не плодите варианты ролей.
- Периодически пересматривайте роли: удаляйте неиспользуемые, объединяйте почти одинаковые.
- Показывайте в админке, что именно разрешает каждая роль, понятным языком.
Пример: админка интернет-магазина
- Роли: Владелец, Администратор, Контент-менеджер, Поддержка, Склад.
- Права:
products.edit,orders.view,orders.refund,users.manage,settings.payments. - Атрибутные правила: поддержка видит заказы, но делает возврат только до лимита из настроек; склад видит только заказы своего склада; никто не может менять собственные роли.