Escapeshellcmd: примеры (PHP)

Функция escapeshellcmd в PHP: полный обзор и практическое применение
Раздел: Безопасность/безопасность shell
escapeshellcmd(string $command): string
Основные сведения о функции escapeshellcmd

escapeshellcmd - это встроенная функция PHP, предназначенная для экранирования потенциально опасных символов в строке, которая будет передана в системную оболочку (shell) для выполнения.

Когда используется

Функция применяется в ситуациях, когда необходимо безопасно сформировать команду для выполнения через функции вроде exec(), system(), passthru() или оператор `backtick`. Она предотвращает выполнение произвольных команд, экранируя символы, имеющие специальное значение для оболочки.

Аргументы

Функция принимает один обязательный параметр:

string escapeshellcmd ( string $command )
  • $command - строка, содержащая команду для экранирования.

Возвращает экранированную строку команды.

Простые примеры использования

Пример базового экранирования:


$command = "echo 'Hello & World' && ls -la";
echo escapeshellcmd($command);
echo 'Hello & World' &\&\& ls -la

Экранирование имени файла с пробелами:


$filename = "my file.txt; rm -rf /";
$safe_cmd = "cat " . escapeshellcmd($filename);
echo $safe_cmd;
cat my\ file.txt\;\ rm\ -rf\ /

Использование с exec():


$user_input = "./script.sh; cat /etc/passwd";
$safe_input = escapeshellcmd($user_input);
exec("ls " . $safe_input, $output);
print_r($output);
// Выведет результат команды 'ls ./script.sh\;\ cat\ /etc/passwd'
// Произвольная команда не выполнится
Похожие функции в PHP

Добавляет одинарные кавычки вокруг строки и экранирует существующие одинарные кавычки. Более надежна для экранирования отдельных аргументов команды.


echo escapeshellarg("O'Reilly's book");
'O'\''Reilly'\''s book'
Когда что использовать

escapeshellcmd применяется для экранирования всей команды, когда нужно предотвратить добавление новых команд через ;, &&, |. escapeshellarg предпочтительнее для безопасной передачи отдельных аргументов, так как полностью изолирует их в кавычках. В большинстве случаев escapeshellarg считается более безопасным выбором.

Аналоги в других языках
Python (subprocess module)

Использует передачу аргументов списком, что исключает необходимость экранирования через shell.


import subprocess
subprocess.run(['ls', '-la', 'my file.txt'])

При необходимости использования shell=True применяют shlex.quote():


import shlex
print(shlex.quote("echo 'test' && ls"))
'echo '\''test'\'' && ls'
JavaScript (Node.js, child_process)

Аналогично Python, рекомендуется передавать аргументы массивом:


const { spawn } = require('child_process');
const ls = spawn('ls', ['-la', 'my file.txt']);

Escapeshellcmd в MySQL

Для экранирования shell-команд не применяется, но есть функции для экранирования SQL-запросов (mysql_real_escape_string()), которые решают схожие задачи безопасности на другом уровне.

Отличия от PHP

В отличие от PHP, современные практики в Python и Node.js предполагают минимальное использование shell, предпочитая прямое выполнение команд с раздельными аргументами, что фундаментально безопаснее.

Типичные ошибки
Неполное экранирование при конкатенации

Ошибочно экранировать части команды по отдельности:


// Неправильно!
$cmd = escapeshellcmd('ls -la') . ' ' . escapeshellcmd($_GET['dir']);
// Если $_GET['dir'] = "/tmp; cat /etc/passwd"
// Результат: ls\ -la /tmp\;\ cat\ /etc/passwd
// Команда 'cat' не выполнится, но структура нарушена

Правильный подход - экранировать всю команду целиком или использовать escapeshellarg для аргументов:


$cmd = 'ls -la ' . escapeshellarg($_GET['dir']);
Ложное чувство безопасности

escapeshellcmd не защищает от всех угроз и не должна быть единственной мерой безопасности:


// Функция не экранирует пробелы внутри аргументов
$cmd = escapeshellcmd('cat /etc/passwd');
exec($cmd); // Команда ВЫПОЛНИТСЯ!

Для таких случаев нужно валидировать или ограничивать входные данные.

Неправильное использование с путями к файлам

// Может сломать пути на Windows
$path = 'C:\Program Files\app.exe';
echo escapeshellcmd($path);
C:Program Filesapp.exe  // Обратные слеши удалены!
История изменений функции
PHP 8.0.0

В Windows экранирование стало более безопасным: теперь экранируются символы ^, &, %, (, ), [, ], {, }, =, ;, !, +, ~, ,, ", ', <, >, | и пробел.

Предыдущие версии

В PHP 5.4.0 и 5.4.1 функция экранировала символ #. Начиная с PHP 5.4.2, этот символ больше не экранируется, так как он не представляет опасности в контексте shell-команд.

Кроссплатформенные различия

Поведение функции различается на Unix-системах и Windows из-за различий в shell. В Unix экранируются #&;`|*?~<>^()[]{}$\'"\x0A\xFF, а в Windows - дополнительный набор символов, специфичный для cmd.exe.

Расширенные примеры применения
Комбинация с escapeshellarg для сложных команд
Пример php

$user = "O'Connor";
$file = "data; echo 'inject'";
$cmd = sprintf(
    "convert %s -resize 800x600 %s",
    escapeshellarg($user),
    escapeshellarg($file)
);
echo escapeshellcmd($cmd);
convert 'O'\''Connor' -resize 800x600 'data; echo '\''inject'\'''
Обработка пользовательского ввода для find
Пример php

$pattern = ".php -exec rm {} \\;";
$safe_pattern = escapeshellcmd($pattern);
$command = "find /var/www -name '*$safe_pattern'";
echo $command;
find /var/www -name '*\\.php\ -exec\ rm\ \{\}\ \\\;'
Экранирование в Windows-среде
Пример php

$cmd = "dir C:\Users & echo Vulnerable";
echo escapeshellcmd($cmd);
dir C:Users ^& echo Vulnerable
Создание безопасного wrapper для shell-команд
Пример php

function safe_shell_exec($base_cmd, $user_input) {
    $full_cmd = $base_cmd . ' ' . escapeshellcmd($user_input);
    // Дополнительная проверка на допустимые символы
    if (preg_match('/[^a-zA-Z0-9_\-\.\/\s]/', $user_input)) {
        return "Invalid characters detected";
    }
    return exec($full_cmd);
}
echo safe_shell_exec('ls -la', '/tmp; cat /etc/passwd');
// Выполнится: ls -la /tmp\;\ cat\ /etc/passwd
Работа с pipe и перенаправлениями
Пример php

$cmd = "cat log.txt | grep 'error' > errors.txt";
echo escapeshellcmd($cmd);
cat log.txt \| grep 'error' \> errors.txt
Эмуляция частичного экранирования

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

Пример php

function escape_specific($cmd, $chars = ';&|') {
    return preg_replace('/([' . preg_quote($chars, '/') . '])/', '\\\\$1', $cmd);
}
echo escape_specific("echo test; ls", ';');
echo test\; ls

PHP escapeshellcmd function comments

En
Escapeshellcmd Escape shell metacharacters