
Уязвимость mod_php: риски и как защитить сайты
mod_php запускает PHP внутри Apache с правами одного пользователя: взлом одного сайта открывает доступ к другим. Разберём риски и защиту.
Уязвимость mod_php: почему один взломанный сайт открывает доступ ко всем
Главная уязвимость mod_php — отсутствие изоляции: PHP работает внутри Apache под одним системным пользователем, поэтому скрипт любого сайта на сервере видит и меняет всё, что доступно этому пользователю.
Модуль mod_php много лет был способом запуска PHP по умолчанию: он прост и не требует отдельных сервисов. Но у простоты есть цена. Ниже разберём, как устроен риск, как он проявляется на практике, какие ошибки конфигурации его усиливают и как перейти на более безопасную схему без остановки сайтов.
Как работает mod_php
mod_php (в системе это библиотека `libphp`) подключается к веб-серверу Apache как обычный модуль. Интерпретатор PHP загружается прямо в рабочие процессы Apache. Когда приходит запрос к файлу `.php`, Apache не обращается к отдельной программе: он сам выполняет код внутри своего процесса. Поэтому mod_php быстр и прост в настройке.
У этой схемы есть следствие. Процессы Apache запускаются от имени одного пользователя, указанного в конфигурации: `www-data` в Debian и Ubuntu, `apache` в семействе RHEL. Значит, и PHP-код каждого виртуального хоста исполняется с одними и теми же правами. Для операционной системы разницы между `site-a.ru` и `shop-c.ru` нет: это один и тот же пользователь.
Посетитель или бот открывает любую страницу на сервере
Пользователь www-data. Один набор прав на все виртуальные хосты
- /var/www/site-a/wp-config.php
- /var/www/site-b/.env
- /var/www/shop-c/uploads/
Скрипт любого сайта выполняется с теми же правами, а значит видит файлы остальных, если они доступны пользователю Apache.
Что именно уязвимо: общий пользователь и общая память процесса
Риск mod_php складывается из трёх свойств схемы.
1. Общие права. Любой PHP-скрипт может прочитать файлы, доступные пользователю Apache, и записать в каталоги, где у этого пользователя есть запись. Если конфигурационные файлы соседних сайтов читаются «всеми» (например, права 644 или 755), их содержимое получит любой скрипт, включая загруженный злоумышленником веб-шелл.
2. Общий процесс. Код сайта выполняется внутри процесса веб-сервера. Ошибка в расширении PHP или в самом интерпретаторе затрагивает процесс Apache целиком, а не изолированный воркер одного сайта.
3. Слабая защита на уровне PHP. Директива `open_basedir` ограничивает каталоги, к которым обращается PHP, но это программный барьер внутри интерпретатора. Он не заменяет разграничение прав в операционной системе, и защищаться только им ненадёжно.
Как выглядит атака на практике
Типичный сценарий начинается не с mod_php, а с уязвимого плагина, устаревшей CMS или формы загрузки файлов без проверки. Злоумышленник заливает на сайт небольшой PHP-скрипт (веб-шелл). Дальше всё определяет то, под каким пользователем он выполняется.
При mod_php этот скрипт получает права `www-data`. Он читает `wp-config.php` и `.env` соседних проектов, забирает пароли от баз данных, перебирает каталоги в `/var/www`, внедряет вредоносный код в чужие файлы, если у пользователя Apache есть на них запись. В итоге заражается не один сайт, а весь сервер. Владельцы замечают это обычно по спаму в выдаче Яндекса и Google или по санкциям в панелях вебмастеров.
Пять ошибок настройки, которые усиливают риск mod_php
Как делают
- Выдают каталогам и файлам права 777 «чтобы заработала загрузка»
- Подключают обработчик через AddHandler без привязки к концу имени файла, и файл shell.php.jpg выполняется как PHP
- Оставляют разрешённым запуск PHP в каталогах uploads и cache
- Рассчитывают только на open_basedir как на защиту от соседних сайтов
- Годами не обновляют PHP и работают на версии, снятой с поддержки
Как правильно
- 01
Файлы — 640, каталоги — 750, запись только там, где она действительно нужна
- 02
Использовать FilesMatch с якорем на конец имени (расширение .php строго в конце) и запрещать двойные расширения
- 03
Отключать выполнение PHP в каталогах загрузок правилами веб-сервера
- 04
Разграничивать сайты правами ОС: отдельные пользователи и пулы PHP-FPM
- 05
Использовать поддерживаемую ветку PHP 8.x и своевременно ставить обновления безопасности
Prefork, память и риск отказа в обслуживании
Второй блок проблем связан с производительностью, но он влияет и на безопасность. Классическая сборка PHP для mod_php не потокобезопасна, поэтому Apache приходится запускать в режиме `prefork`: один процесс на одно соединение. Каждый такой процесс несёт в памяти интерпретатор PHP и расширения, даже если отдаёт обычную картинку или файл стилей.
Предел `MaxRequestWorkers` быстро заканчивается. Медленные соединения в стиле Slowloris, всплеск ботов или спонтанный наплыв посетителей занимают все процессы, и сайт перестаёт отвечать. При PHP-FPM статику отдаёт веб-сервер, а PHP вызывается только для динамических запросов, поэтому тот же сервер выдерживает заметно больше одновременных подключений.
| Параметр | mod_php | PHP-FPM | CGI + suEXEC |
|---|---|---|---|
| Пользователь PHP | Один для всех (www-data или apache) | Свой пользователь у каждого пула | Владелец сайта |
| Изоляция сайтов | Практически отсутствует | Высокая, на уровне ОС | Высокая |
| Режим Apache (MPM) | Обычно prefork | Event или worker | Любой |
| Нагрузка и память | PHP в каждом процессе, включая отдачу статики | PHP только там, где он нужен | Запуск процесса на каждый запрос, медленно |
| Настройки отдельного сайта | php_value в .htaccess | Файл пула и .user.ini | Гибко, но дорого по ресурсам |
Когда mod_php ещё допустим
Говорить, что mod_php нужно удалить везде, неверно. Если на сервере работает один сайт или несколько проектов одного владельца, где компрометация одного всё равно означает компрометацию остальных, изоляция нужна меньше. На небольшом лендинге или учебном стенде mod_php не создаёт дополнительного риска по сравнению с другими схемами.
Переходить стоит, когда на сервере размещены сайты разных владельцев или клиентов, работает интернет-магазин с платёжными данными и персональными данными покупателей, нагрузка растёт и Apache упирается в память, либо к безопасности есть формальные требования. В этих случаях разграничение прав операционной системой становится обязательным.
Как перейти с mod_php на PHP-FPM
- 01
Проведите инвентаризацию. Выясните, какие модули загружены (`apachectl -M`), какая версия PHP работает (`php -v`) и какие сайты используют `php_value` и `php_flag` в `.htaccess`: при PHP-FPM эти директивы не работают.
- 02
Установите PHP-FPM той же ветки, что используется сейчас, и перенесите в него конфигурацию `php.ini`: лимиты памяти, загрузки файлов, время выполнения.
- 03
Создайте отдельный пул и пользователя для каждого сайта. В настройках пула укажите `user`, `group` и собственный сокет, например `/run/php/site-a.sock`.
- 04
Поменяйте владельцев файлов. Каталоги сайта должны принадлежать его пользователю, права — 750 для каталогов и 640 для файлов. Запись разрешайте только в нужные каталоги.
- 05
Переключите Apache. В Debian и Ubuntu отключите модуль PHP (`a2dismod php8.x`) и режим prefork (`a2dismod mpm_prefork`), включите `mpm_event` и `proxy_fcgi`, затем направьте обработку `.php` на сокет нужного пула через `SetHandler`.
- 06
Проверьте и перезагрузите. Прогоните `apachectl configtest`, откройте каждый сайт, проверьте формы, загрузку файлов и административные разделы, а затем выполните плавную перезагрузку веб-сервера.
- 07
Закрепите результат. Отключите опасные функции через `disable_functions`, выставьте `expose_php=Off` и `display_errors=Off`, настройте мониторинг логов пулов.
Что проверить после переключения
Чаще всего после миграции ломаются сайты, которые полагались на `.htaccess` с директивами `php_value`. Их нужно перенести в конфигурацию пула или в файл `.user.ini`. Ещё один частый случай — права на каталоги кеша и загрузок: после смены владельца пользователь пула должен иметь в них запись, а остальные — нет.
Чтобы убедиться, что изоляция работает, проверьте простым тестом: создайте на тестовом сайте скрипт, пытающийся прочитать файл соседнего проекта. При правильной настройке он получит отказ в доступе на уровне системы.
Восемь настроек, которые стоит проверить сегодня
Отдельный пул PHP-FPM и системный пользователь на каждый сайт
Права: файлы 640, каталоги 750, нигде нет 777
Запись только в uploads и cache, а в них выполнение PHP запрещено
В disable_functions внесены exec, system, passthru, shell_exec, proc_open, popen
expose_php = Off и display_errors = Off на рабочем сервере
Обработчик PHP привязан к концу имени файла:\.php$
Используется поддерживаемая ветка PHP 8.x с регулярными обновлениями
Файлы .env и wp-config.php вне веб-корня или закрыты правилами сервера
Почему защита работает только в комплексе
Ни одна из этих настроек не спасёт, если остальные игнорируются. Отдельный пул без правильных прав на файлы почти бесполезен, а жёсткие права не помогут, если выполнение PHP в каталоге загрузок остаётся разрешённым. Относитесь к перечню как к набору слоёв: каждый из них снижает вероятность взлома и ограничивает ущерб, если взлом всё же произошёл.
Что даёт отказ от mod_php
- 01
Изоляция сайтов: взлом одного проекта не открывает файлы остальных
- 02
Меньший расход памяти: интерпретатор PHP не загружается ради статических файлов
- 03
Устойчивость к всплескам нагрузки и медленным соединениям благодаря режиму event
- 04
Индивидуальные лимиты ресурсов и параметры PHP для каждого сайта
- 05
Перезапуск отдельного пула без остановки всего веб-сервера
- 06
Более понятная картина в логах: видно, какой сайт создаёт нагрузку или ошибки
Что делать, если сайт уже взломан
Если признаки компрометации уже есть, важно действовать по порядку. Поспешная чистка без поиска причины почти всегда заканчивается повторным заражением через ту же брешь. При mod_php есть дополнительная сложность: нужно проверять не только пострадавший сайт, но и соседние, потому что скрипт мог добраться до них.
Включить режим обслуживания и отключить заражённый виртуальный хост или пул
Сохранить логи Apache и копию файлов для анализа, пока следы не затёрлись
Проверить недавно изменённые файлы, новые .php в каталогах загрузок, задания cron и учётные записи администраторов
Заменить пароли баз данных, SFTP и админки, обновить ключи и соли, пересобрать файлы из чистого источника
Запросить перепроверку в Яндекс Вебмастере и Google Search Console, если там были предупреждения
Итоги: mod_php — вопрос архитектуры, а не одной дыры
- 01
Для чужих сайтов, интернет-магазинов и серверов под нагрузкой используйте PHP-FPM с отдельным пулом на каждый сайт
- 02
Не полагайтесь на open_basedir как на единственную защиту
- 03
Держите права 640 и 750, запрещайте выполнение PHP в каталогах загрузок
- 04
Обновляйте PHP до поддерживаемой ветки и отключайте опасные функции
- 05
Подключите Яндекс Вебмастер и Google Search Console, чтобы быстро узнавать о заражении
Начните с простого: проверьте, какие модули загружены в Apache, и узнайте, под каким пользователем работают ваши сайты. Если ответ «под одним и тем же», изоляцию стоит планировать уже сейчас, пока взлом не заставил делать это в аварийном режиме.
Часто задаваемые вопросы
Это архитектурная особенность, а не одна конкретная ошибка. mod_php выполняет PHP внутри процессов Apache, поэтому все сайты на сервере работают с правами одного пользователя (www-data или apache). Если взломан один сайт, злоумышленник может добраться до файлов остальных.
Да, если на сервере один сайт или несколько сайтов одного владельца, права на файлы настроены строго, PHP обновлён, а опасные функции отключены. Для хостинга с чужими сайтами и для проектов с повышенными требованиями лучше PHP-FPM с отдельным пулом на каждый сайт.
PHP-FPM запускает отдельные пулы процессов под разными системными пользователями. Скрипт одного сайта не получает прав на каталоги другого, а ограничения задаются на уровне операционной системы, а не только настроек PHP.
Признаки: неизвестные .php-файлы в каталогах загрузок, изменённые даты у ядра CMS, спам-ссылки в выдаче, предупреждения в Яндекс Вебмастере (раздел «Безопасность и нарушения») и в Google Search Console («Проблемы безопасности»).
Проверим, как PHP работает на вашем сервере, и закроем уязвимости
Проведём аудит конфигурации Apache и PHP и подготовим план перехода на PHP-FPM без простоя
Спасибо за заявку!
Мы свяжемся с вами в ближайшее время.
Аудит конфигурации — за один рабочий день



