RCE в PHP: как работает уязвимость и как защитить сайт
Две одинаковые белые воронки с заглушками в носиках, в левой над заглушкой лежит зелёный шарик

RCE в PHP: как работает уязвимость и как защитить сайт

RCE в PHP — уязвимость, позволяющая выполнить произвольный код на сервере. Разбираем причины, примеры и меры защиты сайта.

Удалённое выполнение кода в PHP: что это за уязвимость и как от неё защититься

Удалённое выполнение кода (RCE, Remote Code Execution) в PHP — это уязвимость, при которой внешний пользователь через HTTP-запрос заставляет сервер исполнить произвольный PHP-код или команды операционной системы. Защита строится на трёх основах: не передавать пользовательские данные в опасные функции, своевременно обновлять PHP и CMS, ограничивать права процесса на сервере.

RCE — одна из самых опасных категорий уязвимостей: по шкале CVSS такие ошибки регулярно получают оценки 9–10 из 10, потому что обычно эксплуатируются без авторизации и дают контроль над сервером.

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

Почему RCE в PHP — это не «экзотика»

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

Вторая причина распространённости — масштаб экосистемы. Значительная часть сайтов в Рунете работает на WordPress, 1С-Битрикс, Joomla, Drupal, Laravel и других PHP-платформах. Каждая CMS подтягивает десятки плагинов, модулей и библиотек Composer, и уязвимость в любом из них превращается в точку входа для всего сайта.

Третья причина — «долгая жизнь» устаревших версий. Ветки PHP 7.4 и 8.0 больше не получают официальных исправлений безопасности, но на хостингах и в корпоративных проектах их по-прежнему можно встретить. Любая найденная в них уязвимость остаётся незакрытой навсегда.

Как развивается атака через RCE
01Входные данные

Параметр запроса, cookie, заголовок или загружаемый файл

→
02Опасная точка

eval, include, unserialize или вызов системной команды без фильтрации

→
03Исполнение

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

→
04Закрепление

Веб-шелл, новые админ-аккаунты, задания в cron

Как возникает удалённое выполнение кода в PHP

В основе любой RCE-уязвимости лежит одна и та же схема: данные, которые контролирует пользователь, попадают в место, где они интерпретируются как код или команда. Достаточно, чтобы фильтрация отсутствовала или была реализована неполно.

Выделяют несколько типичных механизмов. Первый — динамическое вычисление кода: функция eval, а в PHP до 8.0 также assert со строковым аргументом, превращают строку в исполняемый код. Второй — запуск системных команд через system, exec, shell_exec, passthru, proc_open, popen и обратные кавычки. Третий — подключение файлов через include и require, когда путь частично или полностью формируется из параметров запроса. Четвёртый — небезопасная десериализация: unserialize на недоверенных данных позволяет создавать объекты и запускать цепочки магических методов (__wakeup, __destruct), которые в итоге приводят к выполнению кода. Пятый — загрузка файлов без проверки типа и каталога: вместо картинки на сервер попадает PHP-скрипт, доступный по прямой ссылке.

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

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

Вектор RCEТипичная причинаОсновная защита
Динамический код (eval, assert)Пользовательская строка попадает в вычисляемое выражениеОтказаться от eval, использовать явную логику или шаблонизатор
Подключение файлов (include/require)Путь к файлу берётся из параметра запроса без белого спискаБелый список допустимых значений, запрет allow_url_include
Системные команды (system, exec, shell_exec)Данные формы подставляются в командную строку без экранированияИспользовать встроенные API вместо shell, escapeshellarg как крайняя мера
Десериализация (unserialize)Объект восстанавливается из cookie или поля формыИспользовать JSON, при необходимости unserialize с allowed_classes=false
Загрузка файлов (upload)Нет проверки содержимого и расширения, файл лежит в публичном каталогеХранить файлы вне webroot, запретить исполнение PHP в каталоге загрузок

Реальные уязвимости из экосистемы PHP

Чтобы понять масштаб проблемы, полезно взглянуть на известные случаи. Они показывают, что RCE находят и в самом интерпретаторе, и в связках с веб-сервером, и в популярных фреймворках.

Уязвимость CVE-2024-4577 затронула PHP при работе в режиме CGI на Windows: из-за особенностей преобразования кодировки символов можно было передать интерпретатору дополнительные аргументы и выполнить код. Она была исправлена в версиях 8.1.29, 8.2.20 и 8.3.8. Уязвимость CVE-2019-11043 касалась связки Nginx и PHP-FPM при определённой конфигурации fastcgi_split_path_info и позволяла выполнять код через специально составленный адрес. В фреймворке Laravel ошибка CVE-2021-3129 в компоненте Ignition была опасна при включённом режиме отладки на рабочем сервере. А файл eval-stdin.php из старых версий PHPUnit (CVE-2017-9841), случайно оставленный в публичном каталоге vendor, годами использовался для массовых атак.

реальные случаи в цифрах
9.8оценка CVSS

CVE-2024-4577: RCE в PHP-CGI на Windows без авторизации

8.3.8исправленные версии

Также 8.2.20 и 8.1.29 — обновление закрывает CVE-2024-4577

debugрежим отладки

CVE-2021-3129 в Laravel опасна при включённом APP_DEBUG на боевом сервере

vendorпубличный каталог

CVE-2017-9841: файл PHPUnit, доступный из браузера, даёт выполнение кода

Чем RCE опасна для бизнеса

  1. 01

    Полный доступ к файлам сайта, базе данных и конфигурациям с паролями и API-ключами

  2. 02

    Утечка персональных данных клиентов с рисками по закону № 152-ФЗ

  3. 03

    Размещение скрытых ссылок, редиректов и спам-страниц, портящих репутацию домена

  4. 04

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

  5. 05

    Пометка сайта как опасного в Яндексе и Google, падение трафика и позиций в выдаче

  6. 06

    Простой сайта и затраты на расследование, восстановление и повторный запуск

Для интернет-магазина или сервиса с заявками последствия взлома ощущаются сразу: перестаёт работать форма заказа, из выдачи пропадают страницы, а браузеры показывают предупреждение. Даже после очистки сайта репутацию приходится восстанавливать неделями: поисковые системы повторно проверяют ресурс, а рекламные кабинеты, например Яндекс Директ и Google Ads, могут отклонять объявления на домен с историей заражения.

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

Главная ошибка: доверять данным от пользователя

Большинство RCE в самописном коде возникают из-за того, что разработчик подставляет значение из запроса прямо в опасную функцию, рассчитывая на «честное» поведение пользователя.

Как делать не нужно

  • Подключать файл по имени из параметра, например по значению GET-переменной page
  • Передавать в eval или shell_exec строку, собранную из полей формы
  • Хранить сериализованные объекты в cookie и восстанавливать их через unserialize
  • Проверять расширение загружаемого файла только на стороне браузера
  • Оставлять включённым режим отладки и тестовые скрипты на боевом сервере

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

  1. 01

    Использовать белый список разрешённых значений и сопоставлять их с заранее известными файлами

  2. 02

    Заменить shell-вызовы встроенными функциями PHP или специализированными библиотеками

  3. 03

    Хранить состояние в сессиях на сервере либо в JSON с подписью, а не в сериализованных объектах

  4. 04

    Проверять MIME-тип и содержимое файла, переименовывать его и хранить вне webroot

  5. 05

    Отключать отладку, удалять dev-зависимости командой composer install --no-dev

Защита на уровне сервера и конфигурации

Безопасный код — только половина решения. Вторая половина — настройка среды, которая ограничивает ущерб, если ошибка всё же проскочила. Принцип здесь называется «минимальные привилегии»: процесс PHP должен иметь ровно столько прав, сколько нужно для работы сайта.

Запретите исполнение PHP в каталогах загрузок (uploads, cache, tmp) на уровне Nginx или Apache. Настройте раздельные пользователи и пулы PHP-FPM для разных сайтов, чтобы взлом одного не затронул соседние. Используйте open_basedir, ограничивающий доступ к файловой системе, и отключите неиспользуемые опасные функции в disable_functions. Перед обновлением конфигурации проверьте, что этим функциям не доверяет ни CMS, ни ваши модули, иначе часть возможностей сайта перестанет работать.

конфигурация php.ini: было / стало
allow_url_include
былоOn
сталоOff
display_errors
былоOn
сталоOff, ошибки пишутся в лог
expose_php
былоOn
сталоOff
disable_functions
былопусто
сталоexec, system, shell_exec, passthru, popen, proc_open
open_basedir
былоне задан
сталокаталог сайта и tmp
RCE не то же самое, что SQL-инъекция. Через SQL-инъекцию атакующий работает с базой данных, а при RCE он исполняет код на самом сервере. Часто одно приводит к другому: например, из базы можно получить пароль администратора, а затем загрузить в админке вредоносный плагин.

Как выявлять уязвимости заранее

Системный подход состоит из нескольких регулярных практик. Во-первых, инвентаризация: вы должны знать версию PHP, CMS, каждого плагина и пакета Composer. Команда composer audit проверяет зависимости проекта по базе известных уязвимостей, а подписка на рассылки безопасности вашей CMS помогает узнавать об исправлениях в день выхода.

Во-вторых, статический анализ: инструменты вроде PHPStan и Psalm с правилами безопасности, а также поиск по коду вызовов eval, system, unserialize и include с переменными. В-третьих, мониторинг: следите за изменением файлов (контрольные суммы, git status на сервере), необычной нагрузкой и новыми заданиями cron. Также подключите сайт к Яндекс Вебмастеру и Google Search Console: оба сервиса уведомляют, если обнаружили вредоносный код или взлом, и показывают раздел с проблемами безопасности.

Наконец, периодически проводите тестирование на проникновение на копии сайта. Оно покажет те сценарии, которые не видны при чтении кода.

Что делать, если сайт взломали через RCE

  1. 01

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

  2. 02

    Сохраните доказательства: скопируйте файлы, дамп базы и логи веб-сервера и PHP до начала очистки.

  3. 03

    Найдите точку входа: изучите access-логи на подозрительные запросы с длинными параметрами, обращения к неизвестным PHP-файлам, POST-запросы в каталоги загрузок.

  4. 04

    Восстановите чистый код: разверните ядро CMS, плагины и проект из доверенных источников или репозитория, а не «лечите» заражённые файлы вручную.

  5. 05

    Смените все секреты: пароли администраторов, FTP/SSH, доступ к базе данных, ключи API и соли CMS; удалите незнакомых пользователей и задания cron.

  6. 06

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

  7. 07

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

После инцидента обязательно проведите разбор: что именно позволило атаке состояться, почему не сработал мониторинг и какие процессы нужно изменить. Без этого повторный взлом через несколько недель — очень вероятный сценарий: многие атакующие оставляют «чёрный ход» и возвращаются позднее.

Если вы работали с подрядчиком или хостингом, уточните, какие логи они хранят и за какой срок. Расследование без логов часто превращается в гадание, а закрытие найденной дыры не гарантирует, что других нет.

Итоги: как не допустить RCE в PHP-проекте

Удалённое выполнение кода почти всегда является следствием трёх причин: непроверенный ввод, устаревшее ПО и избыточные права процесса. Устранив каждую, вы закрываете подавляющее большинство реальных сценариев атак.
  1. 01

    Не передавайте данные пользователя в eval, shell-функции, include и unserialize

  2. 02

    Обновляйте PHP, CMS, плагины и пакеты Composer, не используйте версии без поддержки

  3. 03

    Запретите исполнение PHP в каталогах загрузок и используйте раздельные пулы PHP-FPM

  4. 04

    Отключите отладку и dev-зависимости на боевом сервере, настройте disable_functions и open_basedir

  5. 05

    Подключите Яндекс Вебмастер и Google Search Console и храните логи для расследований

Безопасность — это процесс, а не разовое действие. Включите проверку зависимостей в рабочий цикл, регулярно просматривайте логи и тестируйте сайт на копии. Если вы хотите быть уверены, что сайт не содержит уязвимых мест, закажите независимый аудит: эксперт найдёт то, что незаметно при ежедневной работе.

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

Проверьте свой PHP-сайт на уязвимости до того, как это сделают другие

Проведём аудит версий, кода и настроек сервера и пришлём список рисков с приоритетами

Бесплатная первичная оценкаОтчёт за 2 дняБез простоя сайта

Более 70% взломов начинаются с устаревшего ПО

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

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

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

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

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

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

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

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

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

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

Контакты

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