# Привілей

## Що це таке

Привілей — це дозвіл робити те, що система інакше забороняє. Його має людина
або запущена програма, бо так вирішив той, хто має на це повноваження: читати
чужі файли, слухати порт нижче 1024, створювати облікові записи чи викликати
функцію в базі даних. Зазвичай говорять про набір привілеїв, бо суб'єкт рідко
має лише один, а також про «привілейовані» та «непривілейовані» облікові записи
й процеси, щоб показати, з якого боку межі вони стоять. Із привілеями працюють
на кожному рівні, і глосарій NIST додає те, що легко забути: привілеї описують
дозволену поведінку суб'єкта, а визначає їх уповноважена сторона й записує в
політиці чи правилах.

Поруч із цим словом стоять ще два. Контроль доступу — це саме рішення щодо
кожного запиту, а привілей — один із фактів про того, хто питає, на які це
рішення спирається. Дозвіл (permission) зазвичай означає те саме, але з боку
ресурсу: файл каже, хто може його читати, а читач має на це право.

У Linux слово має точне значення. Сторінка посібника capabilities(7) описує
класичний поділ Unix: привілейовані процеси, ефективний ідентифікатор
користувача яких дорівнює 0 і які називають root, обходять усі перевірки дозволів
у ядрі, а кожен інший процес перевіряється за його обліковими даними. Починаючи з
Linux 2.2, ядро ділить повноваження root на окремі одиниці, capabilities, які
можна вмикати й вимикати по одній. Тож програмі, якій треба лише слухати низький
порт, можна дати `CAP_NET_BIND_SERVICE` і нічого більше. Сторінка credentials(7)
пояснює, чию саме ідентичність перевіряють: реальний ідентифікатор показує, хто
володіє процесом, ефективний — це те, що ядро порівнює з дозволами, а збережений
set-user-ID дає програмі змогу відкласти підвищену ідентичність і пізніше
повернутися до неї.

Бази даних і організації вживають те саме слово для власних надань. Роль у базі
даних має привілеї на схеми, таблиці й функції. Обліковий запис адміністратора
має привілеї, яких немає у звичайного працівника. Ідея на кожному рівні та сама:
право, надане свідомо, перетнути межу, яка інакше закрита.

## Чому це важливо

Привілеї програми — це розмір шкоди, яку вона може завдати, коли з нею щось
трапиться. Саме таку мету мають capabilities: скомпрометована програма з вузьким
набором прав шкодить менше, ніж та сама програма, що працює як root. Вебсервер із
вразливістю, яка дає виконати код, і з правами root віддає всю машину тому, хто
знайшов вразливість. Та сама вразливість у процесі, що може читати лише свій
каталог і слухати один порт, дістає дуже мало.

NIST називає це принципом найменших привілеїв. Контроль AC-6 у SP 800-53 вимагає,
щоб організація дозволяла лише ті доступи, які потрібні користувачам і процесам,
що діють від їхнього імені, для виконання їхніх завдань. Розширення цього
контролю перетворюють принцип на щоденну роботу: адміністратори виконують звичайні
справи, як-от пошту, під непривілейованим обліковим записом, привілейовані записи
мають лише ті, кому вони потрібні, використання привілейованих функцій
журналюється, а привілеї переглядають і забирають, коли потребу в них більше
неможливо обґрунтувати.

Типові налаштування рідко починаються з цього. У systemd системний сервіс без
рядка `User=` працює як root, а `NoNewPrivileges=`, параметр, який забороняє
сервісу та його дочірнім процесам отримувати більше прав через `execve()`,
вимкнений, доки хтось його не ввімкне. Інструменти для баз даних часто
під'єднуються як власник усіх таблиць, бо саме так створювали схему. Нових
працівників часто копіюють з облікового запису колеги разом з усіма правами.
Кожне таке налаштування зручне першого дня і дороге того дня, коли стається
злам.

Компроміс тут справжній. Звуження привілеїв потребує часу, бо хтось має з'ясувати,
що програма насправді робить, а надто вузький набір ламає роботу під час
виконання, а не під час встановлення. Тож команда зазвичай вирішує, куди спершу
вкласти цей час: у все, що дивиться в інтернет, у все, що зберігає дані, втрата
яких буде відчутною, і в облікові записи, які можуть змінювати інші облікові
записи. Для покупця чи аудитора корисне запитання просте: хто і що має тут права
адміністратора і чому?

## Як це виглядає на практиці

На власному сервері компанії
[тринадцять unit-файлів працювали з тими привілеями, які наглядач дає за замовчуванням](/uk/portfolio/cut-systemd-sandbox-exposure-across-every-unit-119/),
а це більшість із них. Кожен шаблон отримав стелю привілеїв на рівні самого
юніта, фільтр системних викликів, обмежені родини адрес і пам'ять, яка може бути
доступною для запису або для виконання, але ніколи для обох одночасно. Оцінка
захищеності перемикача мертвої руки знизилася з 9,6 до 1,5, git-форджі —
з 8,3 до 1,5, а двох юнітів резервного копіювання — з 9,6 до 2,3 і 2,5. В одній
із директив у трьох шаблонах виявилася помилка в написанні, і наглядач записував
у журнал невідомий ключ та все одно запускав юніт. Тому тепер під час кожного
зведення кожен юніт проходить власну перевірку наглядача. Сторінка також фіксує,
чого оцінка не враховує: директива, яка ламає юніт, робить це під час роботи.

На платформі застосунку
[API входить у базу даних під роллю з найменшими привілеями](/uk/portfolio/hardened-the-application-with-nonce-based-csp-hsts-77/),
яка може лише виконувати EXECUTE для функцій застосунку, а ті працюють як
SECURITY DEFINER із параметризованими запитами. Права на кшталт тарифу, ролі,
організації та прив'язки до судна перевіряються на сервері при кожному запиті, а
обмеження в інтерфейсі вважаються лише частиною UX.

В одній організації
[ідентичності та доступи зібрали разом у M365, 1Password, Red Hat SSO і OKTA SSO](/uk/portfolio/prevented-security-breaches-by-leading-access-management-initiatives-21/),
застосували принцип найменших привілеїв і стандартизували прийом та звільнення
працівників, тож доступ відкликали одразу, а не залишали після того, як людина
переходила на іншу роботу.

## Де виникають проблеми

**Сервіс працює як root, бо його юніт про користувача мовчить.** Для системного
сервісу наглядач за замовчуванням обирає root, тож юніт без рядка `User=` має
всі привілеї машини. Дайте кожному сервісу власного користувача або дозвольте
systemd виділити його через `DynamicUser=`: користувач з'являється, коли юніт
стартує, і зникає, коли юніт зупиняється.

**Одна capability виявляється майже цілим root.** `CAP_SYS_ADMIN` охоплює так
багато операцій, що її власний посібник називає її перевантаженою і «the new
root». Команда, яка надає її, щоб відкрити одну функцію, фактично надає більшу
частину root. Знайдіть конкретну capability, яка потрібна програмі, і обмежте
bounding set саме нею:

```ini
[Service]
User=web
NoNewPrivileges=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
```

Ці налаштування дають сервісу, що працює від звичайного користувача, слухати
порт 80, а всі інші capabilities прибирають із його bounding set.

**Процес піднімається вище, ніж стартував.** Програма від звичайного користувача
все ще може запустити файл із set-user-ID або файл із прикріпленими capabilities,
і тоді ядро підвищує її привілеї на час цього запуску. Захисники розпізнають це
як процес, у якого ефективний ідентифікатор користувача відрізняється від
реального. `NoNewPrivileges=yes` закриває цей шлях для сервісу і кожного процесу,
який він запускає.

**Права накопичуються, коли люди змінюють посади.** Людина переходить в іншу
команду й зберігає старий доступ поруч із новим, а за кілька років її обліковий
запис має суму всіх ролей, які вона колись мала. AC-6 відповідає на це
періодичним переглядом, а AC-2 — керуванням обліковими записами, прив'язаним до
переведень і звільнень, щоб зміна посади означала й зміну доступу.

**Власний вхід застосунку може все.** Коли API під'єднується як власник схеми,
одна вразливість до ін'єкції дістає кожну таблицю. Роль для входу, яка може лише
викликати функції, потрібні застосунку, робить ту саму вразливість значно меншою
проблемою.

## Що почитати далі

- [Privilege у глосарії NIST CSRC](https://csrc.nist.gov/glossary/term/privilege)
  — визначення з CNSSI 4009 із приміткою, що привілеї визначає уповноважена
  сторона.
- [capabilities(7)](https://man7.org/linux/man-pages/man7/capabilities.7.html)
  — як Linux ділить root на окремі capabilities і як їх несуть потоки.
- [credentials(7)](https://man7.org/linux/man-pages/man7/credentials.7.html)
  — реальний, ефективний, збережений і файловий ідентифікатори користувача та що
  вирішує кожен із них.
- [systemd.exec(5)](https://man7.org/linux/man-pages/man5/systemd.exec.5.html)
  — `User=`, `DynamicUser=`, `NoNewPrivileges=` і параметри для capabilities.
- [NIST SP 800-53 Rev. 5](https://csrc.nist.gov/pubs/sp/800/53/r5/upd1/final)
  — контроль AC-6 про найменші привілеї та розширення, що роблять його рутиною.

<https://engineer.company/uk/glossary/privilege/>
