PHP имеет две тесно связанные функции, escapeshellarg()
и escapeshellcmd()
. Кажется, что они делают подобные вещи, а именно помогают сделать строку более безопасной для использования в system()
/ exec()
/ etc.
Какой из них я должен использовать? Я просто хочу иметь возможность вводить пользовательский ввод и запускать на нем команду, а не все взорвать. Если PHP имел функцию exec-type, которая взяла массив строк (например, argv), который обходит оболочку, я бы использовал это. Подобно функции subprocess.call()
Python.
С http://ie2.php.net/manual/en/function.escapeshellarg.php
escapeshellarg () добавляет одинарные кавычки вокруг строки и кавычки / экранирует любые существующие одинарные кавычки, позволяющие передавать строку непосредственно в функцию оболочки и считая ее единственным безопасным аргументом.
escapeshellarg, как указывает его имя, используется как передающий аргумент (ы) оболочки. Например, вы хотите перечислить текущий каталог,
$dir = "."; system('ls '.escapeshellarg($dir)); escapeshellcmd('ls $dir');
Оба делают подобные вещи и просто зависят от того, как вы справляетесь с своей логикой, убедитесь, что вы нормализуете и проверяете свой ввод, прежде чем напрямую перейти к этим методам для лучшей безопасности.
Как правило, вы захотите использовать escapeshellarg
, сделав один аргумент безопасности оболочки. Вот почему:
Предположим, вам нужно получить список файлов в каталоге. Вы придумали следующее:
$path = 'path/to/directory'; // From user input $files = shell_exec('ls '.$path); // Executes `ls path/to/directory`
(Это плохой способ сделать это, но для иллюстрации переносите со мной)
Это работает «отлично» для этого пути, но предположим, что этот путь был чем-то более опасным:
$path = 'path; rm -rf /'; $files = shell_exec('ls '.$path); // Executes `ls path`, then `rm -rf /`;
Поскольку указанный путь был использован неанитированным, любая команда может быть запущена. Мы можем использовать методы escapeshell*
чтобы попытаться предотвратить это.
Сначала, используя escapeshellcmd
:
$path = 'path; rm -rf /'; $files = shell_exec(escapeshellcmd('ls '.$path)); // Executes `ls path\; rm -rf /`;
Этот метод избегает символов, которые могут привести к запуску нескольких команд, поэтому, в то время как он останавливает основной риск безопасности, он все равно может привести к передаче нескольких параметров.
Теперь, используя escapeshellarg
:
$path = 'path; rm -rf /'; $files = shell_exec('ls '.escapeshellarg($path)); // Executes `ls 'path; rm -rf /'`;
Это дает нам результат, которого мы хотим. Вы заметите, что он цитирует весь аргумент, поэтому отдельные пробелы и т. Д. Не нужно избегать. Если бы аргумент состоял в том, чтобы иметь кавычки, они были бы указаны.
Подводя итог, escapeshellcmd
гарантирует, что строка является только одной командой, а escapeshellarg
делает строку безопасной для использования в качестве одного аргумента для команды.
Простое решение для определения разницы между любыми двумя аналогичными функциями PHP заключается в написании быстрого скрипта командной строки в PHP, который выводит все возможное пространство поиска и просто показывает различия (в данном случае, сравнивая 256 значений):
<?php for ($x = 0; $x < 256; $x++) { if (chr($x) !== escapeshellcmd(chr($x))) echo $x . " - cmd: " . chr($x) . " != " . escapeshellcmd(chr($x)) . "\n"; } echo "\n\n"; for ($x = 0; $x < 256; $x++) { if (chr($x) !== substr(escapeshellarg(chr($x)), 1, -1)) echo $x . " - arg: " . chr($x) . " != " . substr(escapeshellarg(chr($x)), 1, -1) . "\n"; } ?>
Выполнение вышеуказанного в PHP 5.6 на выводах командной строки Windows:
0 - cmd: != 10 - cmd: != ^ 33 - cmd: ! != ^! 34 - cmd: " != ^" 35 - cmd: # != ^# 36 - cmd: $ != ^$ 37 - cmd: % != ^% 38 - cmd: & != ^& 39 - cmd: ' != ^' 40 - cmd: ( != ^( 41 - cmd: ) != ^) 42 - cmd: * != ^* 59 - cmd: ; != ^; 60 - cmd: < != ^< 62 - cmd: > != ^> 63 - cmd: ? != ^? 91 - cmd: [ != ^[ 92 - cmd: \ != ^\ 93 - cmd: ] != ^] 94 - cmd: ^ != ^^ 96 - cmd: ` != ^` 123 - cmd: { != ^{ 124 - cmd: | != ^| 125 - cmd: } != ^} 126 - cmd: ~ != ^~ 255 - cmd: != ^ 0 - arg: != 33 - arg: ! != 34 - arg: " != 37 - arg: % != 92 - arg: \ != \\
Запуск того же скрипта под версиями PHP 5.5 для Linux:
0 - cmd: != 10 - cmd: != \ 34 - cmd: " != \" 35 - cmd: # != \# 36 - cmd: $ != \$ 38 - cmd: & != \& 39 - cmd: ' != \' 40 - cmd: ( != \( 41 - cmd: ) != \) 42 - cmd: * != \* 59 - cmd: ; != \; 60 - cmd: < != \< 62 - cmd: > != \> 63 - cmd: ? != \? 91 - cmd: [ != \[ 92 - cmd: \ != \\ 93 - cmd: ] != \] 94 - cmd: ^ != \^ 96 - cmd: ` != \` 123 - cmd: { != \{ 124 - cmd: | != \| 125 - cmd: } != \} 126 - cmd: ~ != \~ 128 - cmd: != ... 255 - cmd: ÿ != 0 - arg: != 39 - arg: ' != '\'' 128 - arg: != ... 255 - arg: ÿ !=
Главное отличие заключается в том, что PHP escapeshellcmd () под Windows префиксами символов с кареткой ^ вместо обратного слэша \. Честности под Linux из chr (128) через chr (255) для escapeshellcmd () и escapeshellarg () можно объяснить использованием недействительных кодовых точек UTF-8, отбрасываемых, усеченных или неверно истолкованных.
Также следует отметить, что escapeshellarg () избегает гораздо меньшего количества символов и все еще выполняет свою работу.
Что касается общей безопасности и безопасности системы и приложений, вам лучше использовать escapeshellarg () и индивидуально избегать каждого аргумента, который состоит из пользовательского ввода.
Один из примеров:
echo escapeshellarg("something here") . "\n"; echo escapeshellarg("'something here'") . "\n"; echo escapeshellarg("\"something here\"") . "\n";
Выходы Windows:
"something here" "'something here'" " something here "
Выходы Linux:
'something here' ''\''something here'\''' '"something here"'
PHP escapeshellarg () в Windows окружает строку символом двойной кавычки, в то время как Linux использует символ одной кавычки. PHP на Windows полностью заменяет внутренние двойные кавычки пробелами (что может быть проблемой в некоторых случаях). Linux немного отстает, чтобы избежать одиночных кавычек и обратных косых черт \ экранировано \\ в Windows. PHP escapeshellarg () в Windows также заменяет! И% символов пробелами. Все платформы заменяют \ 0 пробелами.
Обратите внимание, что поведение не обязательно согласовано между версиями PHP, и документация PHP не всегда отражает реальность. Написание быстрого сценария или чтение исходного кода PHP – это два способа выяснить, что происходит за кулисами.
В документах PHP написано различие:
escapeshellcmd :
Следующим символам предшествует обратная косая черта: # &; `| *? ~ <> ^ () [] {} $ \, \ X0A и \ xFF. 'и "экранируются только в том случае, если они не спарены. В Windows все эти символы плюс% заменяются пробелом.
escapeshellarg :
добавляет одинарные кавычки вокруг строки и кавычки / экранирует любые существующие одинарные кавычки, позволяющие передавать строку непосредственно в функцию оболочки и считая ее единственным безопасным аргументом.
Источник:
http://www.php.net/manual/en/function.escapeshellcmd.php http://www.php.net/manual/en/function.escapeshellarg.php