АНДРЕЙ ШЕТУХИН, руководитель почтовой службы Rambler
Как работает suexec
Безопасность – одна из самых важных задач индустрии веб-хостинга. Вторая, не менее значимая, задача – построить систему, удобную для пользователя. Рассмотрим принцип работы одного из инструментов для построения подобной системы – Apache suexec.
Apache suexec впервые появился в версии 1.2 и с тех пор зарекомендовал себя как стабильный и простой инструмент для безопасного запуска пользовательских скриптов. Тем не менее следует отметить, что неправильная настройка или непонимание принципов работы suexec могут привести к печальным последствиям для всего веб-хостинга. Поэтому детальное знание принципов работы suexec необходимо любому администратору веб-сервиса.
Прежде всего надо понимать, для чего предназначен suexec: для безопасного запуcка CGI-сценариев. Поскольку ключевой момент – безопасность, suexec делает множество разнообразнейших проверок, призванных предотвратить возможные попытки взлома системы. Общая схема работы Apache следующая: веб-сервер Apache, как правило[1], запускается от пользователя root, но работает от непривилегированного пользователя, обычно от пользователя www, www-data, apache или nobody (зависит от ОС). Переход от root к непривилегированному пользователю производится системными вызовами setgid и setuid. Вызовы setgid и setuid доступны только пользователю root. Это означает, что никаким образом в рамках одного процесса невозможно из пользователя www стать пользователем username. Будь это не так, ОС UNIX-like были бы дырявы, как решето.
Как же решить задачу исполнения CGI-сценариев от указанного нами в конфигурации Apache пользователя?
Ответ прост: воспользоваться программой suexec.
Схема работы suexec
Suexec – программа, выполняющая CGI-сценарий от указанного владельца. В рамках одного процесса невозможно сменить одного непривилегированного пользователя на другого. Поэтому suexec – отдельная suid-программа, запускающаяся на каждое исполнение CGI-сценария от пользователя root и работающая с правами указанного пользователя. Давайте рассмотрим права доступа к suexec:
ls -la /usr/local/sbin/suexec
-rws--x--x 1 root wheel 10292 30 май 13:58
/usr/local/sbin/suexec* |
Символ s в правах доступа означает установленный suid bit. Программа с установленным suid bit независимо от того, кто ее запустил, исполняется от того пользователя, кому принадлежит. Suexec принадлежит root, поэтому, когда Apache его запускает, он работает с правами root.
Далее все просто: suexec делает необходимые проверки и выполняет вызовы setgid и setuid, устанавливая владельца и его группу. Потом запускается требуемый CGI-сценарий. Схематично все описанное выглядит так, как показано на рисунке. Вот, собственно, и весь алгоритм. Дальнейший материал будет посвящен детальному описанию проверок, производимых suexec перед вызовом CGI-сценария.
Конфигурация suexec
Запуск suexec возможен двумя способами:
- С параметром -V. В этом случае печатается набор опций, с которыми была собрана программа.
- С 3 параметрами командной строки: именем пользователя, именем группы и путем к запускаемому сценарию.
Вывод опций может выглядеть примерно так:
-D AP_DOC_ROOT="/home"
-D AP_GID_MIN=1000
-D AP_HTTPD_USER="www"
-D AP_LOG_EXEC="/var/log/apache/suexec_log"
-D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
-D AP_UID_MIN=1000
-D AP_USERDIR_SUFFIX="www
|
Кратко остановимся на каждой:
AP_DOC_ROOT – каталог, в котором возможен запуск CGI-сценариев. В данном случае – /home и все его подкаталоги. Программы, расположенные в других каталогах, например, в /usr, исполняться не будут.
AP_GID_MIN, AP_UID_MIN – минимальный UID и GID владельца, для которого разрешен запуск CGI.
AP_HTTPD_USER – имя пользователя, от которого запущен Apache. Никто, кроме указанного пользователя, использовать по назначению suexec не может. В случае попытки в лог будет записано сообщение: user mismatch (имя_пользователя instead of www).
AP_LOG_EXEC – имя лог-файла suexec.
AP_SAFE_PATH – список путей, признанных безопасными. Здесь перечислены дополнительные каталоги, откуда возможен запуск программ.
AP_USERDIR_SUFFIX – имя каталога, откуда следует запускать программу в случае, если имя пользователя указано в виде '~username.
AP_SUEXEC_UMASK – маска прав при создании файлов и каталогов.
Алгоритм работы и проверок suexec
Список с примерами ошибок дан в соответствии с последовательностью проверок в коде suexec.c.
- Очистка переменных окружения. Допустимыми считаются только те переменные, что указаны в списке:
- HTTP_*
- SSL_*
- AUTH_TYPE=
- CONTENT_LENGTH=
- CONTENT_TYPE=
- DATE_GMT=
- DATE_LOCAL=
- DOCUMENT_NAME=
- DOCUMENT_PATH_INFO=
- DOCUMENT_ROOT=
- DOCUMENT_URI=
- GATEWAY_INTERFACE=
- HTTPS=
- LAST_MODIFIED=
- PATH_INFO=
- PATH_TRANSLATED=
- QUERY_STRING=
- QUERY_STRING_UNESCAPED=
- REMOTE_ADDR=
- REMOTE_HOST=
- REMOTE_IDENT=
- REMOTE_PORT=
- REMOTE_USER=
- REDIRECT_HANDLER=
- REDIRECT_QUERY_STRING=
- REDIRECT_REMOTE_USER=
- REDIRECT_STATUS=
- REDIRECT_URL=
- REQUEST_METHOD=
- REQUEST_URI=
- SCRIPT_FILENAME=
- SCRIPT_NAME=
- SCRIPT_URI=
- SCRIPT_URL=
- SERVER_ADMIN=
- SERVER_NAME=
- SERVER_ADDR=
- SERVER_PORT=
- SERVER_PROTOCOL=
- SERVER_SIGNATURE=
- SERVER_SOFTWARE=
- UNIQUE_ID=
- USER_NAME=
- TZ=
- Проверка существования учетной записи пользователя, от которого запускается suexec.
- Проверка соответствия имени пользователя, запустившего suexec и AP_HTTPD_USER.
root!machine# suexec stellar stellar /bin/ls
[2008-10-31 12:34:14]: user mismatch (root instead of www)
|
- Проверка пути к запускаемому CGI-скрипту. Путь к запуcкаемому сценарию не должен начинаться с «/» и «../», а также не должен содержать «/../».
www!machine$ suexec stellar stellar /bin/ls
[2008-10-31 12:36:20]: invalid command (/bin/ls) |
- Проверка существования пользователя (по имени или по ID).
www!machine$ suexec stellar nonexistent ./ls
[2008-10-31 15:14:34]: invalid target group name: (nonexistent)
|
www!machine$ suexec stellar 88888 ./ls
[2008-10-31 15:10:55]: invalid target group id: (88888) |
- Проверка существования группы пользователя (по имени или по ID).
www!machine$ suexec nonexistent nonexistent ./ls
[2008-10-31 15:10:47]: invalid target user name: (nonexistent)
|
www!machine$ suexec 77777 88888 ./ls
[2008-10-31 15:10:55]: invalid target user id: (77777)
|
- Проверка AP_GID_MIN, AP_UID_MIN – минимальных UID и GID владельца, для которых разрешен запуск CGI.
www!machine$ suexec root 0 ./ls
[2008-10-31 15:16:03]: cannot run as forbidden uid (0/./ls)
|
www!machine$ suexec stellar 0 ./ls
[2008-10-31 15:16:03]: cannot run as forbidden gid (0/./ls)
|
- Далее производится вызов setgid и setuid. Если возникла ошибка, выдается сообщение:
www!machine$ suexec stellar stellar ./ls
[2008-10-31 15:24:01]: uid: (ashetuhin/ashetuhin) gid: (ashetuhin/ashetuhin) cmd: ./ls
[2008-10-31 15:24:01]: failed to setgid (1001: ./ls)
[2008-10-31 15:24:01]: failed to setuid (1001: ./ls) |
Обычно это означает, что неверно выставлены права на программу suexec, а точнее, что не установлен suid bit.
- Проверка на запуск скрипта из userdir. Если имя пользователя задано с тильдой (~), осуществляется переход в домашний каталог пользователя, а затем – в каталог, заданный в AP_USERDIR_SUFFIX. Если имя пользователя задано без тильды, осуществляется проверка на вхождение текущего каталога в AP_DOC_ROOT.
www!machine$ suexec stellar stellar ./ls
[2008-10-31 15:39:20]: cannot get docroot information (/usr/local/www/data)
|
- Проверка прав доступа к текущему рабочему каталогу.
- Проверка невозможности записи в рабочий каталог для всех, кроме владельца.
- Проверка прав доступа к запускаемому сценарию.
www!machine$ suexec stellar stellar ./ls
[2008-10-31 16:05:39]: cannot stat program: (./nonexistent) |
- Проверка невозможности записи в файл CGI-сценария для всех, кроме владельца.
www!machine$ suexec stellar stellar ./ls
[2008-10-31 16:08:50]: file is writable by others: (/usr/local/www/data/stellar/./ls) |
- Проверка отсутствия установленных на файл CGI-сценария suid- и sugid-флагов.
www!machine$ suexec stellar stellar ./ls
[2008-10-31 16:09:34]: file is either setuid or setgid: (/usr/local/www/data/stellar/./ls)
|
- Проверка совпадения владельца, группы каталога и запускаемого сценария с указанными в параметрах командной строки suexec.
www!machine$ suexec stellar stellar ./ls
[2008-10-31 15:43:48]: target uid/gid (1001/1001) mismatch with directory (80/80) or program (0/0) |
- Проверка флага execute CGI-сценария.
www!machine$ suexec stellar stellar ./ls
[2008-10-31 16:10:20]: file has no execute permission: (/usr/local/www/data/stellar/./ls) |
- Установка AP_SUEXEC_UMASK.
- Запуск CGI-сценария.
Итак, мы рассмотрели все аспекты работы suexec. Несмотря на то что технологии CGI и SSI все более вытесняются mod_(php|perl|python) и FastCGI, до сих пор существует большое количество приложений, для безопасной работы которых требуется suexec. Надеюсь, статья поможет в освоении этого полезного инструмента.