Зачем мне использовать chroot для песочницы для безопасности, если мое приложение с самого начала может работать на более низком уровне?

14

Я пишу демон HTTP-сервера на C (есть причины, почему), управляя им с помощью системного файла модуля.

Я переписываю приложение, разработанное 20 лет назад, примерно в 1995 году. И система, которую они используют, заключается в том, что они выполняют chroot, а затем setuid, и стандартную процедуру.

Теперь, в моей предыдущей работе, обычной политикой было то, что вы никогда не запускаете какой-либо процесс от имени пользователя root. Вы создаете пользователя / группу для него и запускаете оттуда. Конечно, система выполняла некоторые функции от имени пользователя root, но мы могли выполнить всю обработку бизнес-логики, не будучи пользователем root.

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

Разве не безопаснее запускать его как mydaemon-user с самого начала? Вместо того, чтобы запускать его с правами root, chrooting, а затем setuid для mydaemon-user?

мур
источник
3
вам нужно работать с правами суперпользователя, чтобы использовать порт 80 или 443. в противном случае вы можете сделать то, что делает tomcat и другое программное обеспечение веб-приложения / веб-сервера, и запустить его на более высоком порту (скажем, 8080, 9090 и т. д.), а затем использовать либо apache / nginx для прокси соединения с программным обеспечением вашего веб-сервера или использования брандмауэра системы для NAT / пересылки трафика на ваш веб-сервер через порт 80. Если вам не нужен порт 80 или 443, или вы можете прокси или перенаправить соединение, тогда вам не нужно запускаться от имени root, в chroot или как-то иначе.
SnakeDoc
3
@SnakeDoc в Linux больше не соответствует действительности. Спасибо capabilities(7).
0xC0000022L
@SnakeDoc вы можете использовать authbind , а также
Абдул Ахад

Ответы:

27

Похоже, что другие не поняли вашу точку зрения, которая не была причиной, по которой нужно использовать измененные корни, что, конечно же, вы уже ясно знаете, и что еще вы можете сделать, чтобы установить ограничения на демонов, когда вы также четко знаете о работе под эгидой непривилегированные учетные записи пользователей; но зачем делать это внутри приложения . На самом деле есть пример того, почему.

Рассмотрим дизайн httpdпрограммы демона в пакете публичных файлов Дэниела Дж. Бернштейна. Первое, что он делает, это меняет root на корневой каталог, который ему было сказано использовать с аргументом команды, затем отбрасывает привилегии для непривилегированного идентификатора пользователя и идентификатора группы, которые передаются в двух переменных среды.

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

Можно подумать, что можно извлечь функциональность httpdи использовать такие специальные инструменты. Тогда, как вы предполагаете, ни одна часть серверной программы никогда не запускается с привилегиями суперпользователя.

Проблема в том, что в качестве прямого следствия нужно выполнить значительно больше работы для настройки измененного корня, и это открывает новые проблемы.

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

Но переместить изменение корневого каталога из в программу цепи нагрузки (или Systemd), и вдруг программный файл изображения для httpd, любых общих библиотек , которые он загружает, а также любые специальные файлы /etc, /runи /devчто загрузчик программы или C Runtime библиотеки доступа во время инициализации программы (которые вы можете найти весьма удивительно , если truss/ straceс или C ++ программа), также должны присутствовать в измененном корне. Иначе httpdне может быть прикован к цепи и не будет загружаться / работать.

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

Ничего из этого не имеет место, когда httpdменяет root и сам отбрасывает привилегии.

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

Вот почему это не так просто, как делать все внешне для сервисной программы.

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

дальнейшее чтение

JdeBP
источник
+1, виновен, как предъявлено обвинение. Я нашел название и последний абзац двусмысленными, и если вы правы, я упустил суть. Этот ответ дает очень практическую интерпретацию. Лично я бы прямо отметил, что создание среды chroot, подобной этой, является дополнительным усилием, которого большинство людей хотело бы избежать. Но 2 пункта безопасности здесь уже хорошо сделаны.
sourcejedi
Еще один момент, о котором следует помнить: если сервер отбрасывает привилегии до обработки какого-либо сетевого трафика, этот привилегированный код не подвергается никаким удаленным эксплойтам.
Касперд
5

Я думаю, что многие детали вашего вопроса могут в равной степени относиться к тому avahi-daemon, на что я смотрел недавно. (Возможно, я пропустил еще одну деталь, которая отличается). Запуск avahi-daemon в 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. (Например, ни один из именованных опций systemd не /runпомещается в черный список , куда мы склонны помещать файлы сокетов Unix).

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

Пожалуйста, прочитайте документы для каждого варианта, который вы используете. Некоторые параметры более эффективны в сочетании с другими, а некоторые доступны не на всех архитектурах ЦП. (Не потому, что процессор плохой, а потому, что порт Linux для этого процессора не был так хорошо спроектирован. Я думаю).

(Здесь есть общий принцип. Это более безопасно, если вы можете писать списки того, что вы хотите разрешить, а не того, что вы хотите запретить. Например, определение chroot дает вам список файлов, к которым у вас есть доступ, и это более надежно чем сказать, что вы хотите заблокировать /home ).

В принципе, вы можете применить все те же ограничения самостоятельно перед setuid (). Это всего лишь код, который вы можете скопировать из systemd. Тем не менее, параметры системного блока должны быть значительно проще для написания, и, поскольку они представлены в стандартном формате, их будет легче читать и просматривать.

Поэтому я настоятельно рекомендую просто прочитать раздел «песочница» man systemd.execна вашей целевой платформе. Но если вы хотите наиболее безопасный дизайн можно, я не боялся бы попробовать chroot(а затем удалить rootпривилегии) в вашей программе , а также . Здесь есть компромисс. Использование chrootнакладывает некоторые ограничения на ваш общий дизайн. Если у вас уже есть дизайн, использующий chroot, и, кажется, он делает то, что вам нужно, это звучит довольно здорово.

sourcejedi
источник
+1 специально для системных предложений.
Mattdm
я многому научился из твоего ответа, если бы стек через поток позволял многократный ответ, я бы тоже принял твой. Мне было интересно, если использование системной песочницы безопаснее, чем chroot / setuid / umask / ...
mur
@mur рад, что тебе понравилось :). Это очень естественный ответ на мой ответ. Поэтому я обновил его снова, чтобы попытаться ответить на ваш вопрос.
sourcejedi
1

Если вы можете положиться на systemd, то безопаснее (и проще!) Оставить песочницу для systemd. (Конечно, приложение может также определить, была ли оно запущено в изолированной программной среде с помощью systemd или нет, и в самой изолированной программной среде, если оно все еще является корневым.) Эквивалентом описанной вами службы будет:

[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больше директив и более подробных описаний. Если вы сделаете свой демон-активируемый сокет ( man 5 systemd.socket), вы даже сможете использовать параметры, связанные с сетью: единственной ссылкой службы на внешний мир будет сетевой сокет, полученный от systemd, и он не сможет подключиться ни к чему другому. Если это простой сервер, который прослушивает только некоторые порты и не требует подключения к другим серверам, это может быть полезно. (На RootDirectoryмой взгляд, параметры, связанные с файловой системой, также могут устареть, так что, возможно, вам больше не придется настраивать новый корневой каталог со всеми необходимыми двоичными файлами и библиотеками.)

Также поддерживаются более новые версии systemd (начиная с версии v232) DynamicUser=yes, где systemd автоматически назначает пользователя службы только для времени выполнения службы. Это означает , что вы не должны зарегистрировать постоянный пользователь для службы, и работаете отлично до тех пор , как служба не пишете ни файловая систему мест , отличных от его StateDirectory, LogsDirectoryи CacheDirectory(вы можете также объявить в единичном файле - смотрите man 5 systemd.exec, опять же - и какой systemd будет управлять, заботясь о том, чтобы правильно назначить их динамическому пользователю).

Лукас Веркмейстер
источник