LXF102:Доверительный PHP
|
|
|
Содержание |
Доверимся PHP
- В определенных кругах разработчиков безопасность PHP ставится под сомнение. Фрэнк Полманн развенчивает многие из этих мифов...
Все мы знаем, что PHP может быть источником весьма серьезных проблем с безопасностью. Регулярно обнаруживаются новые эксплойты, атакующие непосредственно интерпретатор; PHP-программисты часто имеют дело с системами управления контентом (CMS), нередко становясь при этом жертвами взломщиков.
Однако существуют весьма простые способы обеспечить безопасность, приняв во внимание то, на чем базируется работа PHP, а именно, web-сервер. За основу возьмем Apache, хотя часть последующих примеров применима также и к другим серверам.
Как запускать PHP-программы
Разбираться придется с несколькими различными случаями. Программы PHP могут, во-первых, выполняться как CGI-скрипты; во-вторых, запускаться в рамках модуля Apache; и в-третьих, программы PHP можно писать как CGI-скрипты, но выполнять как часть так называемого модуля FastCGI. Скрипты CGI вызывают особенно неприятные проблемы с безопасностью, ибо каждый CGI-скрипт выполняется как отдельный процесс. А каждый процесс, выполняемый web-сервером, наследует идентификатор пользователя (uid) web-сервера, что не есть хорошо, если кто-нибудь заполучит контроль либо над CGI-скриптом, либо над исполняемым файлом Apache: тогда выполнение Apache и всех других CGI-скриптов будут во власти атакующего.
Существуют, однако, способы держать PHP-скрипты в безопасности без обращения к средствам второй линии защиты, вроде применения chroot’а к Apache и оставшейся части пакета {L,M}AMP. Зададимся вопросом о способах присвоить каждому CGI-скрипту отдельный uid; в частности, поговорим о suEXEC. Но есть более фундаментальные приемы, с которыми нужно ознакомиться, прежде чем прибегать к средствам типа suEXEC и suPHP.
Первичное укрепление Apache
Практическую безопасность PHP можно подразделить на четыре части: безопасность файловой системы, безопасность Apache, уровень безопасности PHP-интерпретатора и безопасность PHP-клиента. Первыми тремя мы займемся целиком, а говоря о suEXEC, кратко остановимся на четвертой. Предположим, имеется стандартная схема размещения файлов: все файлы Apache расположены в /usr/local/apache2/.
ServerRoot /usr/local/apache2 DocumentRoot /usr/local/apache2/htdocs Основной конфигурационный файл /usr/local/apache2/conf/httpd.conf Параметры SSL /usr/local/apache2/conf/ssl.conf ErrorLog /usr/local/apache2/logs/error_log AccessLog /usr/local/apache2/logs/access_log cgi-bin /usr/local/apache2/cgi-bin Исполняемые файлы Apache /usr/local/apache2/bin
Можно, а иногда и нужно, иметь несколько каталогов cgi-bin; этим мы воспользуемся при разговоре о местоположении PHP-интерпретатора.
Права доступа и последствия
Следует принять в расчет два сценария: a Различные пользователи не должны иметь возможность случайно или умышленно перезаписывать файлы или каталоги друг друга.
b Каждый пользователь может иметь дело с виртуальной копией Apache, избегая таким образом некоторых, но не всех, проблем с правами доступа.
Данная возможность отражается на производительности и безопасности, но в данном контексте мы ее обсуждать не будем.
Права доступа PHP CGI
Когда PHP скомпилирован для запуска с Apache, и используется файл конфигурации по умолчанию, рабочий режим PHP – это режим CGI-скрипта. Каждый CGI-скрипт, независимо от языка программирования, должен иметь необходимые права доступа, чтобы владелец скрипта мог запустить его. Это значит, что владелец скрипта должен уметь считывать и запускать сам скрипт, а Apache должно быть достаточно только прав на запуск. Если верить документации Apache, права доступа каталогов cgi-bin, где Apache ищет CGI-скрипты, должны быть таковы:
drwxrwxrwx
что также известно как права доступа 0777. Как мы увидим позже, все сценарии внутри каталогов cgi-bin должны восприниматься Apache как CGI-скрипты, и не иначе; отсюда следует, что надо привести в согласие права доступа всех скриптов, размещенных в каталоге cgi-bin (о файлах с данными и с контентом речь пока не идет). Права 0777 допустимы, но это рискованно, так как если вы предоставите их, любая брешь в защите приведет к тому, что люди смогут запросто перезаписывать и даже заменять CGI-скрипты, если они вызываются и модифицируются напрямую.
Строго говоря, единственный пользователь (или группа!), кто во время разработки и тестирования должен иметь право считывать, записывать и получать доступ к каталогу cgi-bin – это web-разработчик, или группа таковых. Тогда права на каталог cgi-bin снижаются до
drwxrwxr-x
они же – права доступа 775. Имеет смысл также предположить, что web-разработчику нужно считывать, изменять и выполнять файлы внутри каталога cgi-bin (и выводить их список!). По завершении разработки, когда CGI-скрипты попали на сервер, группе web-разработчиков в целом, по идее, незачем в них писать.
Выходит, права доступа для cgi-bin – 755, как и сделано по умолчанию на многих установках Apache и пакета LAMP (Linux, Apache, MySQL, и PHP). Они также подразумевают, что пользователь Apache, если таковой существует, сможет выводить список файлов в данном каталоге, исполнять и считывать их.
Права доступа CGI-скрипта
Так как всем остальным пользователям нужно уметь считывать CGI-скрипты, но только Apache приходится их выполнять, администратор должен установить всем CGI-скриптам права 644.
$ chmod 644 {любое_имя_файла}.cgi
Настройка Apache для PHP
Чтобы заставить web-сервер действовать по заданному сценарию, мы должны удостовериться, что прописаны определенные директивы Apache, и присутствуют определенные модули. Прежде всего следует убедиться, что пользователь Apache – единственный, которому система разрешает запускать Apache, и что этот пользователь – единственный член группы Apache. Назовем этого пользователя httpd, и группу тоже назовем httpd.
$ groupadd httpd $ useradd httpd -g httpd -d /dev/null -s /sbin/nologin
Нам нужно создать для Apache нового пользователя, чтобы пресечь любые попытки взломщиков «угадать» владельца скрипта во время работы. Мы не дадим самому Apache многих привилегий: у него даже не будет отдельного входа в систему. Владельцу скриптов и файлов данных, конечно, полагается быть web-разработчиком или кем-то из группы web-дизайна.
Данная мера безопасности окажется бесполезной, только если кто-нибудь сумеет «угадать» идентификатор web-сервера, но для этого требуется несколько больше, чем способность выполнять CGI-скрипты.
Еще нам понадобится возможность создавать другие каталоги cgi, чтобы объединять наши скрипты вместе по типам. Желательно группировать вместе PHP-скрипты, так как можно, а иногда даже нужно, иметь копию интерпретатора PHP, запущенную внутри CGI-каталогов. Обычно считается, что это – дыра в безопасности, но с ней можно управиться способом, которым мы потом займемся отдельно.
UID и GID созданного в системе Linux/Unix пользователя httpd, отображаемые в списке Linux-пользователей, должны совпадать с UID и GID пользователя и группы Apache.
Директивы http.conf, присутствующие в главном разделе конфигурации Apache, таковы:
User httpd Group httpd
Позаботимся, чтобы Apache мог выполнять CGI-скрипты. Это гарантируется модулем mod_cgi (он доступен как часть базового дистрибутива Apache), но существуют некоторые директивы, которые следует добавить к httpd.conf еще до работы модуля. Нам нужно сообщить httpd.conf, что CGI-скрипты могут запускаться, и откуда они могут запускаться. PHP должен запускаться из какого-либо каталога cgi-bin, независимо от того, один или несколько пользователей работают с CGI-скриптами. Мы должны начать с директивы, запрещающей всему, что располагается за пределами дерева web-сервера, запускаться владельцем или любым пользователем Apache. Потом мы сможем ослабить наши правила, но для начала лучше проявить максимум консерватизма.
Следующие директивы тривиальны, но совершенно необходимы для безопасных операций Apache:
<Directory /> Order deny,allow deny from all </Directory>
Это – стандартная директива, она гарантирует, что Apache не сможет обслуживать файлы по всей файловой системе, даже дерево web- сервера. Конечно, теперь придется потрудиться, чтобы Apache СМОГ обслуживать нужные файлы, так что добавим другую директиву, сообщающую, что Apache может обслуживать файлы данных и контента из DocumentRoot:
DocumentRoot /usr/local/apache2/htdocs <Directory /usr/local/apache2/htdocs> Order allow,deny Allow from all </Directory>
Для правильной работы PHP-скрипты обязаны восприниматься как CGI-скрипты.
Чтобы никто не вздумал разрешить выполнение CGI с использованием файлов PHP не из каталога /usr/local/apache2/cgi-bin (или любого другого, явно прописанного вами в директивах Directory), добавим