Безопасность PHP: Чем опасна функция system() при работе с пользовательскими данными и как избежать RCE (Remote Code Execution)?

Функция system() в PHP позволяет выполнять команды операционной системы прямо из PHP-скрипта. Это мощный инструмент, который при неправильном использовании открывает злоумышленникам возможность для Remote Code Execution (RCE) — удалённого выполнения произвольного кода на сервере.

**Почему system() опасна?**

Если пользовательские данные передаются в system() без надлежащей обработки, атакующий может внедрить собственные команды через технику Command Injection. Например:

php
$filename = $_GET[‘file’];
system(«cat /var/www/html/» . $filename);

Злоумышленник передаёт в параметре `file` значение вроде `../../etc/passwd; rm -rf /`, и сервер выполнит сразу несколько команд. Символы `;`, `|`, `&&`, `||`, « ` «, `$()` и другие позволяют объединять команды в shell.

**Последствия успешной RCE-атаки:**
— Полный доступ к файловой системе сервера
— Кража конфиденциальных данных (пароли, ключи API, базы данных)
— Установка вредоносного ПО, веб-шеллов, майнеров
— Удаление или модификация файлов
— Использование сервера как точки для дальнейших атак (pivot)

**Как защититься от RCE через system()?**

1. **Избегайте system() с пользовательскими данными.** Если задачу можно решить средствами PHP (работа с файлами через `file_get_contents`, `fopen` и т.д.) — используйте их.

2. **Используйте escapeshellarg() и escapeshellcmd().** Функция `escapeshellarg()` оборачивает аргумент в одинарные кавычки и экранирует специальные символы:
php
$filename = escapeshellarg($_GET[‘file’]);
system(«cat » . $filename);

Однако это не панацея — лучше не передавать user input в системные команды вообще.

3. **Белый список допустимых значений.** Если нужно принять от пользователя имя файла или команду — проверяйте его по строгому белому списку:
php
$allowed = [‘report’, ‘log’, ‘stats’];
$file = $_GET[‘file’];
if (!in_array($file, $allowed, true)) {
die(‘Недопустимое значение’);
}
system(«cat /reports/» . $file . «.txt»);

4. **Отключите опасные функции в php.ini.** В продакшн-среде можно запретить вызов system(), exec(), passthru(), shell_exec() через директиву:

disable_functions = system, exec, passthru, shell_exec, popen, proc_open

5. **Запускайте PHP с минимальными привилегиями.** Веб-сервер не должен работать от root. Используйте отдельного пользователя с ограниченными правами.

6. **Применяйте WAF (Web Application Firewall).** Инструменты вроде ModSecurity помогут блокировать типичные паттерны Command Injection на уровне HTTP-запросов.

7. **Регулярно проводите аудит кода** с помощью статических анализаторов (PHPStan, Psalm, RIPS) и тестирование на проникновение.

**Вывод:** функция system() сама по себе не является уязвимостью, но становится критически опасной при передаче в неё необработанных пользовательских данных. Лучшая защита — избегать использования system() с user input, а при необходимости — строго валидировать и экранировать все входящие данные.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.