Повышение уровня безопасности LAMP при помощи директивы Apache Proxy mod_proxy

Ник Маинард (Nick Maynard)

Проект по разработке HTTP-сервера фонда Apache Software Foundation, известный как Apache, в настоящее время является преобладающим Web-сервером в Интернете, согласно статистическим данным он занимает более 60 процентов рынка. Все больше и больше Apache используется как часть набора свободного программного обеспечения в конфигурации, известной как LAMP, Web-платформа, построенная на базе технологий с открытыми исходными кодами Linux, Apache, MySQL и PHP. Из этой статьи вы узнаете о способе, позволяющем повысить безопасность установки LAMP путем использования модуля mod_proxy и нескольких внутренних серверов. Я расскажу вам о достоинствах и недостатках такого подхода, и вы увидите пример конфигурации работающей установки.

PHP и Apache: проблемы безопасности

Одна из проблем, с которой сталкиваются администраторы LAMP -- предоставление всех возможностей полной установки PHP и, в то же время, обеспечение безопасного окружения для всех пользователей системы. Использование безопасного режима PHP -- один из методов достижения этой цели, но это также может чрезмерно ограничить пользователей, и некоторые PHP-приложения просто не будут функционировать, когда включен этот режим.

Корень проблемы безопасности PHP лежит в том, как сконфигурировано большинство Apache-серверов. Поскольку большинство установок Apache работает под специальным пользовательским идентификатором www-data, весь пользовательский хостинг Web-сайта должен по умолчанию гарантировать, что файлы пользователей будут доступны для чтения этим пользователям. Следовательно есть вероятность, что все пользовательские файлы, доступные через Web, будут доступны всем другим пользователям системы и могут подвергнуться атаке со стороны других, не имеющих отношения к данной системе. Положение становится даже более сложным, когда файлы или каталоги должны быть доступны для записи для пользователя www-data.

Вы можете отчасти избежать этой проблемы при запуске программ CGI, например, написанных с использованием популярных языков Perl и Python, используя механизм suEXEC. Говоря коротко, suEXEC использует специальную промежуточную программу для выполнения программы CGI под пользовательским идентификатором, который является владельцем программы. Это очень эффективный механизм, традиционно использовавшийся в течение многих лет.

Однако хостинг страниц PHP с использованием модуля mod_php выполняется как часть основного процесса Apache. Собственно, страницы PHP наследуют все мандаты процесса Apache, и поэтому любые выполняемые на файловой системе действия должны выполняться от имени пользователя www-data.

Запуск Apache с использованием различных пользовательских идентификаторов

Очевидное решение описанной выше проблемы -- хостинг всех запросов для пользовательских доменов от копии Apache, которая имеет только этот пользовательский мандат. Вы можете сконфигурировать Apache так, чтобы при запуске принимать любые пользовательские мандаты. Это может решить проблему для несложных конфигураций, где каждому пользователю назначается индивидуальная комбинация IP адрес/порт, доступная через Интернет.

Для более сложных конфигураций, где IP-адреса пользуются большим спросом, этот метод не работает. Вы можете использовать только виртуальный хостинг -- метод, широко распространенный в установках Apache, где единственная копия Apache контролирует особую комбинацию IP адрес/порт. Это предотвращает возможность хостинга множества доменов, принадлежащих множеству пользователей с одной и той же комбинации IP адрес/порт.

В Apache 2.0 вводится понятие мультипроцессорных модулей (MPM). Среди модулей, предоставляемых с пакетом Apache 2.0, присутствует экспериментальный модуль perchild , позволяющий осуществлять виртуальный хостинг при множестве пользовательских идентификаторов путем назначения distributor-потока для комбинации IP адрес/порт и передачи запросов на satellite-потоки, выполняющиеся под индивидуальными пользовательскими мандатами. К сожалению, perchild оставался экспериментальным и функционировал только в случае удачи и в конце концов был удален из официального Apache, начиная с версии 2.2. Перед этим, понимая, что необходимость в наличии стабильного функционирующего perchild-подобного модуля сохраняется, сообщество Apache начало работу по созданию модулей MPM, способных заполнить образовавшийся пробел. Разработка MetuxMPM и его подпроцесса, созданного через fork, peruser, явилась продолжением работ по достижению этой цели.

Решение: mod_proxy

Несмотря на то, что нет официального Apache MPM, пригодного для непосредственного предоставления виртуального хостинга с использованием различных пользовательских идентификаторов, вы все же можете создать систему Apache, работающую таким образом, путем разумного конфигурирования и администрирования. Основное понятие метода -- использование модуля mod_proxy, который в числе других функций позволяет Apache перенаправлять запросы страниц на другие серверы и передавать ответ обратно клиенту, от которого поступил запрос.

Листинг 1. Пример конфигурации обратного прокси для переадресации основного запроса

                ProxyRequests Off

ProxyPass /foo http://foo.example.com/bar
ProxyPassReverse /foo http://foo.example.com/bar 

Код в Листинге 1 -- простой пример, в котором показано перенаправление запроса любой страницы хоста /foo на соответствующую страницу, размещаемую на http://foo.example.com/bar. Например, страница /foo/index.htm будет перенаправлена на http://foo.example.com/bar/index.htm. Вы можете использовать этот принцип для решения проблемы.

Пример сценария

Рассмотрим сценарий, в котором администратор Apache должен предоставить хостинг для двух доменов, принадлежащих двум разным клиентам. Один клиент -- недавно созданная онлайн компания, которая беспокоится об онлайн безопасности. Другой является частным лицом. Он не заботится о безопасности сайта и известно, что он загружает на свой сайт небезопасный код. Учитывая эти моменты, администратор Apache должен предпринять действия для изоляции этих сайтов друг от друга.

Таким образом, у администратора имеется два домена: www.startup.tld, принадлежащий недавно созданной онлайн компании (идентификатор пользователя startup ), и www.reckless.tld, принадлежащий частному лицу (идентификатор пользователя nimrod ). Для решения проблемы администратор принял решение использовать mod_proxy. Администратор выдал каждому пользователю его собственную копию Apache, запущенную под его собственным ID на приватной комбинации IP-адрес/порт, и использовал решение mod_proxy для предоставления доступа к обоим доменам через наружный сервер, запущенный под ID www-data на публичной комбинации IP-адрес/порт. Законченный сценарий показан на Рисунке 1.

Рисунок 1. Образец сценария
Образец сценария

Рекомендуемые версии Apache

Для каждого элемента конфигурации в нашем образце приложения администратор Apache должен использовать версии Apache, перечисленные в Таблице 1.

Таблица 1. Версии Apache, использованные в примере приложения

Элемент Версия Apache Объяснение
Внешний сервер Apache 2, выполняющий MPM worker или MPM event Apache 2 добавляет важное расширение для модуля mod_proxy. MPM worker и MPM event выполняются в виде thread'ов и помогают уменьшить непроизводительный расход памяти на внешнем сервере.
Внутренние серверы Apache 1.3, или Apache 2, выполняющие prefork MPM Администратор Apache должен осознавать, что модуль PHP не должен запускаться под thread-окружением. Эти два варианта предлагают основанные на порождении процессов окружения для модуля PHP.

Конфигурирование внутренних Apache instance

Фрагменты Листингов 2 и 3 иллюстрируют важные моменты конфигурирования, отличающиеся от стандартной конфигурации Apache. Их необходимо добавлять в случае необходимости. Так, в пример конфигурации не включена функциональность PHP.

Листинг 2. Конфигурация Apache для недавно созданной онлайн компании

                # Stuff every Apache configuration needs
ServerType standalone
LockFile /var/lock/apache/accept.startup.lock
PidFile /var/run/apache.startup.pid

ServerName necessaryevil.startup.tld
DocumentRoot "/home/startup/web"

# Essential modules
LoadModule access_module /usr/lib/apache/1.3/mod_access.so

# Which user to run this Apache configuration as
User startup
Group startup

# This must be off else the host isn't passed correctly
UseCanonicalName Off

# The IP/port combination to listen on
Listen 127.0.0.2:10000

# Using name-based virtual hosting allows you to host multiple sites per IP/port combo
NameVirtualHost 127.0.0.2:10000

<VirtualHost 127.0.0.2:10000>
        ServerName www.startup.tld

        # You can add aliases so long as the facade server is aware of them!
        ServerAlias startup.tld

        DocumentRoot "/home/startup/web/www.startup.tld"

        <Directory /home/startup/web/www.startup.tld/>
            Options Indexes FollowSymLinks MultiViews ExecCGI Includes
            AllowOverride All
            Order allow,deny
            Allow from all
        </Directory>

</VirtualHost>

Листинг 3. Конфигурация Apache для частного клиента

                # Stuff every Apache configuration needs
ServerType standalone
LockFile /var/lock/apache/accept.nimrod.lock
PidFile /var/run/apache.nimrod.pid

ServerName necessaryevil.nimrod.tld
DocumentRoot "/home/nimrod/web"

# Essential modules
LoadModule access_module /usr/lib/apache/1.3/mod_access.so

# Which user to run this Apache configuration as
User nimrod
Group nimrod

# This must be off else the host isn't passed correctly
UseCanonicalName Off

# The IP/port combination to listen on
Listen 127.0.0.2:10001

# Using name-based virtual hosting allows you to host multiple sites per IP/port combo
NameVirtualHost 127.0.0.2:10001

<VirtualHost 127.0.0.2:10001>
        ServerName www.reckless.tld

        # You can add aliases so long as the facade server is aware of them!
        ServerAlias reckless.tld

        DocumentRoot "/home/nimrod/web/www.reckless.tld"

        <Directory /home/nimrod/web/www.reckless.tld/>
            Options Indexes FollowSymLinks MultiViews ExecCGI Includes
            AllowOverride All
            Order allow,deny
            Allow from all
        </Directory>

</VirtualHost>

В Листинге 4 показана конфигурация для внешнего instance Apache.

Листинг 4. Конфигурация Apache для внешнего instance Apache

                # Stuff every Apache configuration needs
LockFile /var/lock/apache/accept.www-data.lock
PidFile /var/run/apache.www-data.pid

ServerName necessaryevil.facade.server
DocumentRoot "/home/www-data"

# Essential modules
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so

# Which user to run this Apache configuration as
User www-data
Group www-data

# These must be set else the host isn't passed correctly
UseCanonicalName Off
ProxyVia On
ProxyRequests Off
# This must also be set, though it's only an option in Apache2
ProxyPreserveHost On    

# The IP/port combination to listen on
Listen 9.20.1.1:80

# Using name-based virtual hosting allows you to host multiple sites per IP/port combo
NameVirtualHost 9.20.1.1:80

# Configuration to forward requests for startup.tld
<VirtualHost 9.20.1.1:80>
        ServerName www.startup.tld
        ServerAlias startup.tld

        ProxyPass / http://127.0.0.2:10000/
        ProxyPassReverse / http://127.0.0.2:10000/
        ProxyPassReverse / http://www.startup.tld:10000/
        ProxyPassReverse / http://startup.tld:10000/
</VirtualHost>

# Configuration to forward requests for reckless.tld
<VirtualHost 9.20.1.1:80>
        ServerName www.reckless.tld
        ServerAlias reckless.tld

        ProxyPass / http://127.0.0.2:10001/
        ProxyPassReverse / http://127.0.0.2:10001/
        ProxyPassReverse / http://www.reckless.tld:10001/
        ProxyPassReverse / http://reckless.tld:10001/
</VirtualHost>

Здесь важно отметить директиву ProxyPreserveHost. Эта директива появилась, начиная с версии Apache 2. Она решает некоторые проблемы перенаправления на внутренние серверы корректных заголовков HTTP. Настоятельно рекомендуется использовать Apache 2 instance в качестве внешнего сервера.

Запуск примера конфигурации

Все конфигурации выполняет пользователь root. Apache берет привилегии, требуемые конфигурационным файлом для всех связанных с хостингом процессов. В Листинге 5 показано, как это запустить.

Листинг 5. Запуск серверов примера

                /usr/sbin/apache -f /etc/apache/startup.tld.conf
/usr/sbin/apache -f /etc/apache/nimrod.tld.conf
/usr/sbin/apache2 -f /etc/apache2/facade.tld.conf

Ограничения mod_proxy

Крайне важно заметить, что метод, описанный в этой статье, не будет работать с доменами, требующими SSL-соединений. Это происходит потому, что протокол SSL не позволяет виртуальный хостинг доменов. Вследствие этого ограничения любой SSL-хостинг должен осуществляться способом, когда каждый домен SSL имеет хостинг на своей собственной комбинации IP/порт. Это ограничение касается всех конфигураций Apache, не только тех, которые используют это решение. Тем не менее вы можете запускать домены SSL под идентификатором пользователя их владельца.

Заключение

Из этой статьи вы узнали об использовании возможностей модуля Apache mod_proxy для построения окружения, состоящего из внешнего сервера, пересылающего запросы на два внутренних сервера. Такой подход позволяет системным администраторам исключить возможные риски, связанные с безопасностью, и в то же время сохранять гибкость, предоставляемую такими инструментами, как PHP.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=5457