Уязвимость mod_php: риски и как защитить сайты
Стопка из трёх белых плашек со сквозным отверстием, через которое проходит зелёный шарик

Уязвимость mod_php: риски и как защитить сайты

mod_php запускает PHP внутри Apache с правами одного пользователя: взлом одного сайта открывает доступ к другим. Разберём риски и защиту.

Уязвимость mod_php: почему один взломанный сайт открывает доступ ко всем

Главная уязвимость mod_php — отсутствие изоляции: PHP работает внутри Apache под одним системным пользователем, поэтому скрипт любого сайта на сервере видит и меняет всё, что доступно этому пользователю.

Это не баг в коде, а особенность архитектуры. Именно поэтому её нельзя «закрыть патчем», только перестроить схему запуска PHP.

Модуль 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` нет: это один и тот же пользователь.

схема · один процесс, все сайты
01Запрос

Посетитель или бот открывает любую страницу на сервере

→
02Apache + mod_php

Пользователь www-data. Один набор прав на все виртуальные хосты

→
03Доступно всем скриптам
  • /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 и работают на версии, снятой с поддержки

Как правильно

  1. 01

    Файлы — 640, каталоги — 750, запись только там, где она действительно нужна

  2. 02

    Использовать FilesMatch с якорем на конец имени (расширение .php строго в конце) и запрещать двойные расширения

  3. 03

    Отключать выполнение PHP в каталогах загрузок правилами веб-сервера

  4. 04

    Разграничивать сайты правами ОС: отдельные пользователи и пулы PHP-FPM

  5. 05

    Использовать поддерживаемую ветку PHP 8.x и своевременно ставить обновления безопасности

Prefork, память и риск отказа в обслуживании

Второй блок проблем связан с производительностью, но он влияет и на безопасность. Классическая сборка PHP для mod_php не потокобезопасна, поэтому Apache приходится запускать в режиме `prefork`: один процесс на одно соединение. Каждый такой процесс несёт в памяти интерпретатор PHP и расширения, даже если отдаёт обычную картинку или файл стилей.

Предел `MaxRequestWorkers` быстро заканчивается. Медленные соединения в стиле Slowloris, всплеск ботов или спонтанный наплыв посетителей занимают все процессы, и сайт перестаёт отвечать. При PHP-FPM статику отдаёт веб-сервер, а PHP вызывается только для динамических запросов, поэтому тот же сервер выдерживает заметно больше одновременных подключений.

Параметрmod_phpPHP-FPMCGI + suEXEC
Пользователь PHPОдин для всех (www-data или apache)Свой пользователь у каждого пулаВладелец сайта
Изоляция сайтовПрактически отсутствуетВысокая, на уровне ОСВысокая
Режим Apache (MPM)Обычно preforkEvent или workerЛюбой
Нагрузка и памятьPHP в каждом процессе, включая отдачу статикиPHP только там, где он нуженЗапуск процесса на каждый запрос, медленно
Настройки отдельного сайтаphp_value в .htaccessФайл пула и .user.iniГибко, но дорого по ресурсам

Когда mod_php ещё допустим

Говорить, что mod_php нужно удалить везде, неверно. Если на сервере работает один сайт или несколько проектов одного владельца, где компрометация одного всё равно означает компрометацию остальных, изоляция нужна меньше. На небольшом лендинге или учебном стенде mod_php не создаёт дополнительного риска по сравнению с другими схемами.

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

Как перейти с mod_php на PHP-FPM

  1. 01

    Проведите инвентаризацию. Выясните, какие модули загружены (`apachectl -M`), какая версия PHP работает (`php -v`) и какие сайты используют `php_value` и `php_flag` в `.htaccess`: при PHP-FPM эти директивы не работают.

  2. 02

    Установите PHP-FPM той же ветки, что используется сейчас, и перенесите в него конфигурацию `php.ini`: лимиты памяти, загрузки файлов, время выполнения.

  3. 03

    Создайте отдельный пул и пользователя для каждого сайта. В настройках пула укажите `user`, `group` и собственный сокет, например `/run/php/site-a.sock`.

  4. 04

    Поменяйте владельцев файлов. Каталоги сайта должны принадлежать его пользователю, права — 750 для каталогов и 640 для файлов. Запись разрешайте только в нужные каталоги.

  5. 05

    Переключите Apache. В Debian и Ubuntu отключите модуль PHP (`a2dismod php8.x`) и режим prefork (`a2dismod mpm_prefork`), включите `mpm_event` и `proxy_fcgi`, затем направьте обработку `.php` на сокет нужного пула через `SetHandler`.

  6. 06

    Проверьте и перезагрузите. Прогоните `apachectl configtest`, откройте каждый сайт, проверьте формы, загрузку файлов и административные разделы, а затем выполните плавную перезагрузку веб-сервера.

  7. 07

    Закрепите результат. Отключите опасные функции через `disable_functions`, выставьте `expose_php=Off` и `display_errors=Off`, настройте мониторинг логов пулов.

Что проверить после переключения

Чаще всего после миграции ломаются сайты, которые полагались на `.htaccess` с директивами `php_value`. Их нужно перенести в конфигурацию пула или в файл `.user.ini`. Ещё один частый случай — права на каталоги кеша и загрузок: после смены владельца пользователь пула должен иметь в них запись, а остальные — нет.

Чтобы убедиться, что изоляция работает, проверьте простым тестом: создайте на тестовом сайте скрипт, пытающийся прочитать файл соседнего проекта. При правильной настройке он получит отказ в доступе на уровне системы.

чек-лист · усиление защиты PHP

Восемь настроек, которые стоит проверить сегодня

01

Отдельный пул PHP-FPM и системный пользователь на каждый сайт

02

Права: файлы 640, каталоги 750, нигде нет 777

03

Запись только в uploads и cache, а в них выполнение PHP запрещено

04

В disable_functions внесены exec, system, passthru, shell_exec, proc_open, popen

05

expose_php = Off и display_errors = Off на рабочем сервере

06

Обработчик PHP привязан к концу имени файла:\.php$

07

Используется поддерживаемая ветка PHP 8.x с регулярными обновлениями

08

Файлы .env и wp-config.php вне веб-корня или закрыты правилами сервера

Почему защита работает только в комплексе

Ни одна из этих настроек не спасёт, если остальные игнорируются. Отдельный пул без правильных прав на файлы почти бесполезен, а жёсткие права не помогут, если выполнение PHP в каталоге загрузок остаётся разрешённым. Относитесь к перечню как к набору слоёв: каждый из них снижает вероятность взлома и ограничивает ущерб, если взлом всё же произошёл.

Что даёт отказ от mod_php

  1. 01

    Изоляция сайтов: взлом одного проекта не открывает файлы остальных

  2. 02

    Меньший расход памяти: интерпретатор PHP не загружается ради статических файлов

  3. 03

    Устойчивость к всплескам нагрузки и медленным соединениям благодаря режиму event

  4. 04

    Индивидуальные лимиты ресурсов и параметры PHP для каждого сайта

  5. 05

    Перезапуск отдельного пула без остановки всего веб-сервера

  6. 06

    Более понятная картина в логах: видно, какой сайт создаёт нагрузку или ошибки

Что делать, если сайт уже взломан

Если признаки компрометации уже есть, важно действовать по порядку. Поспешная чистка без поиска причины почти всегда заканчивается повторным заражением через ту же брешь. При mod_php есть дополнительная сложность: нужно проверять не только пострадавший сайт, но и соседние, потому что скрипт мог добраться до них.

таймлайн · реакция на взлом
01
Изолировать

Включить режим обслуживания и отключить заражённый виртуальный хост или пул

02
Зафиксировать

Сохранить логи Apache и копию файлов для анализа, пока следы не затёрлись

03
Найти точку входа

Проверить недавно изменённые файлы, новые .php в каталогах загрузок, задания cron и учётные записи администраторов

04
Почистить и сменить доступы

Заменить пароли баз данных, SFTP и админки, обновить ключи и соли, пересобрать файлы из чистого источника

05
Подтвердить в панелях

Запросить перепроверку в Яндекс Вебмастере и Google Search Console, если там были предупреждения

Предупреждения о заражении появляются в Яндекс Вебмастере (раздел «Безопасность и нарушения») и в Google Search Console («Проблемы безопасности»). Подключите оба сервиса заранее: уведомления о вредоносном коде обычно приходят раньше, чем владелец замечает падение трафика.

Итоги: mod_php — вопрос архитектуры, а не одной дыры

Уязвимость mod_php заключается в том, что все сайты исполняются под одним пользователем внутри процесса Apache. Закрывается она изоляцией, а не заплаткой.
  1. 01

    Для чужих сайтов, интернет-магазинов и серверов под нагрузкой используйте PHP-FPM с отдельным пулом на каждый сайт

  2. 02

    Не полагайтесь на open_basedir как на единственную защиту

  3. 03

    Держите права 640 и 750, запрещайте выполнение PHP в каталогах загрузок

  4. 04

    Обновляйте PHP до поддерживаемой ветки и отключайте опасные функции

  5. 05

    Подключите Яндекс Вебмастер и Google Search Console, чтобы быстро узнавать о заражении

Начните с простого: проверьте, какие модули загружены в Apache, и узнайте, под каким пользователем работают ваши сайты. Если ответ «под одним и тем же», изоляцию стоит планировать уже сейчас, пока взлом не заставил делать это в аварийном режиме.

Часто задаваемые вопросы

Проверим, как PHP работает на вашем сервере, и закроем уязвимости

Проведём аудит конфигурации Apache и PHP и подготовим план перехода на PHP-FPM без простоя

Бесплатный первичный аудитБез остановки сайтовОтчёт с приоритетами

Аудит конфигурации — за один рабочий день

Политика конфиденциальности

При оставлении заявки на ресурсе «https://gurucontext.ru» пользователи предоставляют следующие сведения:

  • Имя
  • Контактный телефон или Telegram
  • Адрес сайта пользователя (не обязательно)

Также администрация сайта получает данные об IP-адресе посетителей, типе браузера, времени нахождения на сайте и прочие подобные сведения через сервисы статистики.

Использование информации

Вся полученная информация используется администрацией «https://gurucontext.ru» исключительно в целях связи с клиентом.

Защита персональных данных

Компания «https://gurucontext.ru» обязуется не разглашать сведения, полученные от пользователей, и хранит их в защищённом виде.

Предоставление данных третьим лицам

Полученные сведения не передаются третьим лицам, за исключением случаев исполнения обязательств перед клиентом (с его разрешения) и обоснованных требований закона.

Контакты

Телефон: +7 (499) 955-47-00.
E-mail: info@gurucontext.ru.