Забираем у nginx лишние привилегии

nginx — замечательный web-сервер, но, как и практически любой программный продукт, не свободен от ошибок, временами весьма критических.

Архитектура nginx такова, что обычно имеется один привилегированный процесс (запускаемый от всемогущего root) и один или более рабочих процессов (обычно работающих от имени непривилегированного пользователя). Тем не менее, я видел конфигурации, в которых все процессы nginx работают под привилегированным пользователем. Один из примеров — многопользовательский сервер, Document Root сайтов на котором имеет права вида 0700 (запускать несколько nginx и настраивать проксирование — тоже не лучший выход).

Кроме того, за последние неполные пять лет в nginx найдено 112 ошибок (segmentation fault), некоторые из которых теоретически могут дать возможность выполнения произвольного кода в системе (wget http://sysoev.ru/nginx/changes.html -q -O - | grep segmentation | wc -l).

Я не знаю, все ли ошибки затрагивали только рабочие процессы, либо были ошибки в главном процессе — рисковать не хочется. Так и родился модуль ngx_drop_privs.

Данный модуль будет работать, скорее всего, только под Linux, при этом для работы требуется наличие библиотеки libcap и ядра, собранного с поддержкой capabilities (я давно не видел ядра без такой поддержки).

Идея заключается в том, что процессу, который порождает потомков, меняет их UID/GID и периодически меняет владельца log-файлов, привилегий root слишком много. Вполне достаточно CAP_SETUID, CAP_SETGID и CAP_CHOWN (если нужна ротация логов).

CAP_CHOWN — весьма опасная возможность, и если есть возможность её не давать, лучше её не давать :-)

Модуль при инициализации проверяет, запущен ли главный процесс от имени root. Если да, то capabilities сбрасываются на указанные в директиве dropprivs_set_caps.

Директива dropprivs_set_caps является глобальной (как, например, daemon, user и pid) и имеет формат

[-]
View Code nginx configuration
dropprivs_set_caps "строка";

где строка — привилегии в формате, который понимает функция cap_from_text(). Никто не говорил, что будет легко.

На своей тестовой машине я использую такое значение:

[-]
View Code nginx configuration
dropprivs_set_caps "cap_setuid,cap_setgid=ep";

Это равносильно сбросу всех привилегий и установке CAP_SETUID и CAP_SETGID в действующем (effective) и разрешённом (permitted) наборе привилегий.

Те, кому это всё интересно, могут скачать исходный код модуля ngx_drop_privs. Код пока ещё сыроват (да, написан за полтора часа этой ночью) и будет совершенствоваться. Любые предложения/патчи are always welcome. Планируется поддержка chroot, что позволит меньше беспокоиться о CAP_CHOWN и CAP_SETUID.

Сборка модуля:

[-]
View Code Bash
cd /path/to/nginx/source
./configure \ # Здесь идут обычные опции configure
    --add-module=/path/to/ngx_drop_privs
make
Добавить в закладки

Связанные записи

23
Сен
2009

Комментарии к статье «ngx_drop_privs: принцип минимальных привилегий в nginx» (2)  »

  1. Alex says:

    не проще ли сам nginx запустить в chroot?

    • Vladimir says:

      Проще. Но права на CAP_SYS_CHROOT, CAP_MKNOD, CAP_SYS_MODULE у мастер-процесса всё равно нужно отбирать, иначе он может выйти из chroot.

Подписаться на RSS-ленту комментариев к статье «ngx_drop_privs: принцип минимальных привилегий в nginx» Trackback URL: http://blog.sjinks.org.ua/security/648-ngx_drop_privs-minimum-privilege-principle-nginx/trackback/

Оставить комментарий к записи «ngx_drop_privs: принцип минимальных привилегий в nginx»

Вы можете использовать данные тэги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, Вы выражаете своё согласие с Правилами комментирования.

Подписаться, не комментируя