Один інстанс — багато операторів. Як ізолювати дані на рівні запиту замість окремих БД.
Multi-tenancy дозволяє одній інсталяції обслуговувати кілька незалежних операторів — наприклад, кілька територіальних підрозділів одного відомства, або кілька відомств у спільній державній інфраструктурі. Це знижує вартість експлуатації у 3-5 разів. Але неправильна реалізація призводить до витоків між tenant’ами — найгіршого можливого сценарію для регульованих систем.
Multi-tenancy — архітектурний патерн, при якому одна копія застосунку обслуговує кілька незалежних «арендарів» (tenant). Кожен арендар працює з власними даними, налаштуваннями, користувачами; інші арендарі цього не бачать.
Альтернатива — окрема інсталяція на кожного арендара. Це дорого з точки зору інфраструктури і експлуатації, але технічно простіше і більш ізольовано.
| Рівень | Ізоляція | Вартість | Складність | Коли обирати |
|---|---|---|---|---|
| 1. Окрема БД на tenant | Максимальна | Висока | Низька | Tenant’и з різними рівнями захисту, з різними регуляторними вимогами |
| 2. Окрема схема на tenant | Висока | Середня | Середня | Tenant’и з однаковими вимогами, але різними даними |
| 3. Спільна схема, фільтр по tenant_id | Середня | Низька | Висока (правильно зробити складніше) | Тисячі tenant’ів, всі з однаковими вимогами |
Кожен tenant має власну базу даних. Жорстка ізоляція на рівні БД. Підходить для систем, де tenant’и — різні організації з різними рівнями допуску.
Мінуси: висока вартість інфраструктури, складна експлуатація (бекап → 1 на tenant, оновлення схеми → треба прокатати на всіх БД).
Одна БД, кожен tenant — окрема схема всередині. Доступ до tenant’у обмежується через grant на схему. Компроміс між ізоляцією та витратами.
Одна таблиця для всіх tenant’ів, додатковий стовпець tenant_id. Запити завжди фільтруються по tenant_id. Найбільш масштабний підхід — десятки тисяч tenant’ів на одній інсталяції.
Найважливіший: помилка реалізації означає витік. Якщо хоча б один запит не фільтрується по tenant_id — tenant A може побачити дані tenant B.
UBD реалізує рівень 3 через модельний фільтр: всі таблиці моделі повинні мати поле tenant_id і політику авторизації, що обов’язково перевіряє його. Адміністратор не пише фільтри у запитах — вони додаються автоматично у запит. Це усуває помилку «забув додати фільтр».
Конкретно:
tenant_id.tenant_id у запиті результат завжди порожній.tenant_id поточного користувача у всі запити.Розробник не додав фільтр по tenant_id у одному з запитів. Результат — tenant А отримав дані tenant Б. Це найгірша помилка multi-tenant: один прохід через приватність руйнує довіру до системи в цілому.
Запобігання: default deny на рівні фреймворку. Без явного tenant_id у контексті — результат порожній.
Frontend фільтрує по tenant_id, backend — ні. Атакувальник, що звертається безпосередньо до API, отримує всі дані.
Запобігання: авторизація завжди на backend. Frontend-фільтри — тільки для UX, не для безпеки.
Клієнт надсилає GET /api/documents/12345. Backend завантажує документ за ID 12345. Перевірка, що документ належить tenant’у користувача — забута. IDOR-вразливість.
Запобігання: кожне завантаження за ID супроводжується перевіркою tenant_id. Цей чек — частина базової авторизації, не опція.
Кеш у пам’яті зберігає результати по ключу запиту, але не включає tenant_id у ключ. Tenant А виконує запит, кеш зберігає результат. Tenant Б виконує той самий запит — отримує дані А.
Запобігання: ключ кешу обов’язково включає tenant_id.
Аудит multi-tenant систем має дві сторони:
Реалізація: один WORM-журнал з полем tenant_id у кожному записі. Інтерфейс адміністратора платформи — без фільтра. Інтерфейс tenant’у — з обов’язковим фільтром по своєму tenant_id.
Для multi-tenant систем у держсекторі:
UBD дозволяє multi-tenant через model-driven прив’язку всіх таблиць до tenant_id з default deny. Адміністратор моделі декларує tenant_id обов’язковим атрибутом. Авторизація на рівні фреймворку не пропускає запити без явного контексту tenant’а. Це покриває вимоги NIST 800-53 AC-3, AC-4, SC-2 і робить класи помилок «забув фільтр» неможливими.