Чому я буду захищати пісочницю для безпеки, якщо моя програма може з самого початку працювати на нижчому рівні?


14

Я пишу демон на сервері HTTP на C (є причини, чому), керуючи ним файлом системного блоку.

Я переписую програму, розроблену 20 років тому, приблизно в 1995 році. І система, якою вони користуються, полягає в тому, що вони переносять, а потім встановлюють і стандартну процедуру.

Зараз у моїй попередній роботі звичайною політикою було те, що ви ніколи не запускаєте жоден процес як корінь. Ви створюєте для нього користувача / групу і запускаєте звідти. Звичайно, система запускала деякі речі як root, але ми могли досягти всієї обробки бізнес-логіки, не використовуючи root.

Тепер для HTTP-демона я можу запустити його без кореня, якщо я не chroot всередині програми. Тож чи не є більш безпечним для програми ніколи не працювати як root?

Хіба не безпечніше запустити його як mydaemon-користувача з самого початку? Замість того, щоб запускати його з root, chrooting, а потім налаштовувати на mydaemon-user?


3
вам потрібно запустити як root, щоб використовувати порт 80 або 443. в іншому випадку ви можете робити те, що робиться tomcat та інше програмне забезпечення для веб-сервера та працювати на більш високому порту (скажімо, 8080, 9090 тощо), а потім використовувати будь-який apache / nginx проксі підключення до програмного забезпечення вашого веб-сервера або використовуйте брандмауер системи для NAT / пересилання трафіку на ваш веб-сервер з порту 80. Якщо вам не потрібен порт 80 або 443, або ви можете проксі або переслати з'єднання, тоді вам не потрібно запускати як root, chroot чи іншим способом.
SnakeDoc

3
@SnakeDoc в Linux більше не відповідає дійсності. Завдяки capabilities(7).
0xC0000022L

@SnakeDoc ви можете використовувати authbind , а також
Абдул Ахад

Відповіді:


27

Здається, інші пропустили вашу думку, і це було не причиною, чому використовувати змінені корені, що, звичайно, ви вже добре знаєте, а також що ще ви можете зробити, щоб встановити обмеження на dæmons, коли ви також чітко знаєте про біг під егідами непривілейовані облікові записи користувачів; але навіщо робити ці речі всередині програми . Насправді є досить точний приклад того, чому.

Розглянемо дизайн програми httpddæmon у публічному пакеті Daniel Daniel Bernstein. Перше, що він робить, - це змінити root в кореневу директорію, яку йому сказали використовувати з аргументом команди, а потім скинути привілеї на непривілейований ідентифікатор користувача та ідентифікатор групи, які передаються у двох змінних середовища.

Набори інструментів управління Dæmon мають спеціальні інструменти для таких речей, як зміна кореневого каталогу та перехід до непривілейованих ідентифікаторів користувачів та груп. Герріт Пап має пробіг chpst. Мій набір інструментів має chrootі setuidgid-fromenv. Лоран Беркот s6 має s6-chrootі s6-setuidgid. Перп Уейна Маршалла має runtoolі runuid. І так далі. Дійсно, всі вони мають власний набір інструментів М. Бернштейна, setuidgidяк попередник.

Можна було б подумати, що можна витягнути функціональні можливості httpdта використовувати такі спеціальні інструменти. Тоді, як ви передбачаєте, жодна частина серверної програми ніколи не працює з привілеями суперпользователя.

Проблема полягає в тому, що один із прямих наслідків повинен зробити значно більше роботи, щоб створити змінений корінь, і це викриває нові проблеми.

За Бернштейна, httpdяк відомо , єдині файли та каталоги, що знаходяться в дереві кореневих каталогів, - це ті, які мають бути опубліковані у світі. На дереві взагалі нічого немає . Крім того, немає ніяких підстав для будь-якого виконуваного файлу програми зображення існують в цьому дереві.

Але перемістити зміна кореневого каталогу з в програму ланцюга навантаження (або Systemd), і раптом програмний файл зображення для httpd, будь-яких загальних бібліотек , які він завантажує, а також будь-які спеціальні файли /etc, /runі /devщо завантажувач програми або C Runtime бібліотеки доступу під час ініціалізації програми (що може бути вам дуже дивно, якщо ви truss/ straceC або C ++ програма), також повинні бути присутніми у зміненому корені. В іншому випадку httpdне можна прикувати і не завантажувати / не працювати.

Пам'ятайте, що це сервер контенту HTTP (S). Він потенційно може обслуговувати будь-який (читається в усьому світі) файл у зміненому корені. Тепер це включає такі речі, як ваші спільні бібліотеки, завантажувач програми та копії різних файлів конфігурації завантажувача / CRTL для вашої операційної системи. І якщо деякими (випадковими) засобами сервер вмісту має доступ до запису матеріалів, компрометований сервер, можливо, може отримати доступ для запису до зображення програми для httpdсебе або навіть завантажувача програм вашої системи. (Пам'ятаєте , що у вас є два паралельних набору /usr, /lib, /etc, /run, і /devкаталоги , щоб зберегти в безпеці.)

Нічого цього не відбувається, коли httpdзмінюється корінь і відміняється сам привілей.

Таким чином, ви торгували, маючи невелику кількість пільгового коду, який досить легко перевіряти, і він працює безпосередньо на початку httpdпрограми, працює з привілеями суперпользователя; за наявності значно розширеної поверхні атаки файлів і каталогів у зміненому корені.

Ось чому це не так просто, як робити все зовнішньо для сервісної програми.

Зауважте, що це, тим не менш, є мінімальним функціоналом всередині httpdсебе. Весь код, який робить такі речі, як пошук у базі даних облікових записів операційної системи для ідентифікатора користувача та ідентифікатора групи для введення цих змінних середовища, в першу чергу, є зовнішнім для httpdпрограми, у простих автономних командах, таких як аудит, як envuidgid. (І, звичайно , це інструмент UCSPI, тому вона містить жоден з кодів непрослуховуються відповідний TCP порт (и) або приймати з'єднання, ті , будучи областю команд , таких як tcpserver, tcp-socket-listen, tcp-socket-accept, s6-tcpserver4-socketbinder, s6-tcpserver4d, і так далі.)

Подальше читання


+1, винні як стягнуті. Я визнав заголовок і останній абзац неоднозначними, і якщо ви маєте рацію, я пропустив суть. Ця відповідь дає дуже практичне тлумачення. Особисто я прямо зауважу, що необхідність будувати подібне середовище - це додаткові зусилля, яких хотіли б уникнути більшість людей. Але два пункти безпеки тут уже добре зроблені.
sourcejedi

Ще один момент, який слід пам’ятати, полягає в тому, що якщо сервер скидає привілеї, перш ніж обробляє будь-який мережевий трафік, то привілейований код не піддається жодним віддаленим подвигам.
kasperd

5

Я думаю, що багато деталей вашого запитання могло б однаково стосуватися того avahi-daemon, на що я розглядав нещодавно. (Можливо, я пропустив ще одну деталь, яка відрізняється). Запуск avahi-демон в chroot має багато переваг, у випадку, якщо avahi-daemon буде порушений. До них належать:

  1. він не може читати домашній каталог будь-якого користувача та розробляти приватну інформацію.
  2. він не може використовувати помилки в інших програмах, записуючи в / tmp. Існує хоча б одна ціла категорія таких помилок. Наприклад, https://www.google.co.uk/search?q=tmp+race+security+bug
  3. він не може відкрити файл Unix, що знаходиться за межами chroot, який інші демони можуть слухати та читати повідомлення.

Точка 3 може бути особливо приємною, коли ви не використовуєте dbus або подібне ... Я думаю, що avahi-daemon використовує dbus, тому він гарантує збереження доступу до системного dbus навіть зсередини chroot. Якщо вам не потрібна можливість надсилати повідомлення на системний dbus, відмова від цієї здатності може бути дуже приємною функцією безпеки.

управління ним за допомогою файлу системного блоку

Зауважте, що якщо avahi-daemon був переписаний, він може потенційно вирішити покластися на systemd для безпеки та використовувати напр ProtectHome. Я запропонував змінити avahi-daemon, щоб додати ці захисти як додатковий шар, а також деякі додаткові захисти, які не гарантуються chroot. Повний список запропонованих мною варіантів можна переглянути тут:

https://github.com/lathiat/avahi/pull/181/commits/67a7b10049c58d6afeebdc64ffd2023c5a93d49a

Схоже, існує більше обмежень, якими я міг би скористатися, якби avahi-daemon не використовував chroot, деякі з яких згадуються у повідомленні комісії. Я не впевнений, наскільки це стосується, хоча.

Зауважте, захист, який я використовував, не обмежував би демон відкривати файли сокетів Unix (пункт 3 вище).

Іншим підходом було б використання SELinux. Однак ви хотіли б прив’язати свою програму до цього підмножини дистрибутивів Linux. Причиною, чому я позитивно подумав про SELinux, є те, що SELinux обмежує доступ, який мають процеси на dbus, дрібнозернистим способом. Наприклад, я думаю, що ви часто можете очікувати, що systemdїх не буде в списку імен шин, які вам потрібні, щоб мати змогу надсилати повідомлення на :-).

"Мені було цікаво, чи використовувати системну пісочницю безпечніше, ніж chroot / setuid / umask / ..."

Резюме: чому б не обидва? Давайте трохи розшифруємо вище :-).

Якщо ви думаєте про пункт 3, використання chroot забезпечує більше обмеженості. ProtectHome = та його друзі навіть не намагаються бути настільки обмежуючими, як chroot. (Наприклад, жоден із названих системних опцій чорний список /run, де ми, як правило, ставимо файли сокетів Unix).

chroot показує, що обмеження доступу до файлової системи може бути дуже потужним, але не все в Linux - це файл :-). Є системні параметри, які можуть обмежувати інші речі, які не є файлами. Це корисно, якщо програма порушена, ви можете зменшити доступні для неї функції ядра, що може спробувати використати вразливість. Наприклад, avahi-daemon не потрібні розетки Bluetooth, і я думаю, що ваш веб-сервер також не :-). Тому не надайте йому доступ до родини адрес AF_BLUETOOTH. Просто білий список AF_INET, AF_INET6 і, можливо, AF_UNIX, використовуючи цю RestrictAddressFamilies=опцію.

Будь ласка, прочитайте документи для кожної вашої опції. Деякі варіанти є більш ефективними в поєднанні з іншими, а деякі доступні не в усіх архітектурах процесора. (Не тому, що процесор поганий, а тому, що порт для цього процесора не був настільки гарний. Я думаю).

(Тут є загальний принцип. Це більш безпечно, якщо ви можете писати списки того, що ви хочете дозволити, а не того, що ви хочете відмовити. Як визначення chroot дає вам список файлів, до яких ви можете отримати доступ, і цей більш надійний ніж сказати, що ви хочете заблокувати /home).

У принципі, ви можете застосувати всі ті ж самі обмеження перед setuid (). Це всього лише код, який можна скопіювати з systemd. Однак параметри системного блоку повинні бути значно простішими для запису, а оскільки вони є у стандартному форматі, їх слід легше читати та переглядати.

Тому я настійно рекомендую просто прочитати розділ пісочниці man systemd.execна вашій цільовій платформі. Але якщо ви хочете найбільш безпечний дизайн можна, я не боявся б спробувати chroot(а потім видалити rootпривілеї) у вашій програмі , а також . Тут є компроміс. Використання chrootнакладає деякі обмеження на ваш загальний дизайн. Якщо у вас вже є дизайн, який використовує chroot, і він, здається, робить те, що вам потрібно, це звучить досить чудово.


+1 спеціально для системних пропозицій.
mattdm

Я навчився трохи від ур відповіді, якщо стек над потоком дозволив кілька відповідей, я б також прийняв ур. Мені було цікаво, чи використовувати системну пісочницю безпечніше, ніж chroot / setuid / umask / ...
mur

@mur рада, що тобі сподобалось :). Це дуже природна відповідь на мою відповідь. Тому я оновив її ще раз, щоб спробувати відповісти на ваше запитання.
sourcejedi

1

Якщо ви можете покластися на systemd, тоді справді безпечніше (і простіше!) Залишати пісочницю системою. (Звичайно, програма також може виявити, запущена чи пісонізована система systemd чи ні, і сама пісочниця, якщо вона все ще є root.) Еквівалент служби, яку ви описуєте, буде:

[Service]
ExecStart=/usr/local/bin/mydaemon
User=mydaemon-user
RootDirectory=...

Але ми не повинні зупинятися на цьому. systemd також може зробити для вас багато інших пісочниць - ось кілька прикладів:

[Service]
# allocate separate /tmp and /var/tmp for the service
PrivateTmp=yes
# mount / (except for some subdirectories) read-only
ProtectSystem=strict
# empty /home, /root
ProtectHome=yes
# disable setuid and other privilege escalation mechanisms
NoNewPrivileges=yes
# separate network namespace with only loopback device
PrivateNetwork=yes
# only unix domain sockets (no inet, inet6, netlink, …)
RestrictAddressFamilies=AF_UNIX

Дивіться man 5 systemd.execнабагато більше директив та більш детальних описів. Якщо ви зробите свій демон-socket-активаційним ( man 5 systemd.socket), ви навіть можете використовувати параметри, пов’язані з мережею: єдиним посиланням служби на зовнішній світ буде мережевий сокет, який він отримав від systemd, він не зможе підключитися ні до чого іншого. Якщо це простий сервер, який слухає лише деякі порти і не потребує підключення до інших серверів, це може бути корисно. (На RootDirectoryмою думку, параметри, пов’язані з файловою системою, можуть також застаріти, тому, можливо, вам більше не потрібно буде створювати новий кореневий каталог із усіма необхідними бінарними файлами та бібліотеками.)

Новіші версії systemd (починаючи з v232) також підтримують DynamicUser=yes, де systemd автоматично призначить користувача сервісу лише під час виконання служби. Це означає , що ви не повинні зареєструвати постійний користувач для служби, і працюєте відмінно до тих пір , як служба не пишете ні файлова систему місць , відмінних від його StateDirectory, LogsDirectoryі CacheDirectory(ви можете також оголосити в одиничному файлі - дивіться man 5 systemd.exec, ще раз - і який systemd потім керуватиме, подбаючи про те, щоб правильно призначити їх динамічному користувачеві).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.