Какая разница между escapeshellarg и escapeshellcmd?
PHP имеет две тесно связанные функции, escapeshellarg()
и escapeshellcmd()
. Кажется, что они делают подобные вещи, а именно помогают сделать строку более безопасной для использования в system()
/exec()
/etc.
Какой я должен использовать? Я просто хочу иметь возможность вводить пользовательский ввод и запускать на нем команду, а не все взорвать. Если PHP имел функцию exec-type, которая взяла массив строк (например, argv), который обходит оболочку, я бы использовал это. Подобно функции Python subprocess.call()
.
Ответы
Ответ 1
От http://ie2.php.net/manual/en/function.escapeshellarg.php
escapeshellarg() добавляет одинарные кавычки вокруг строки и кавычки/экранирует любой существующие одинарные кавычки, позволяющие вам передать строку непосредственно в оболочку функции и ее следует рассматривать как один безопасный аргумент.
escapeshellarg, как указывает его имя, используется как передающий аргумент оболочки. Например, вы хотите перечислить текущий каталог,
$dir = ".";
system('ls '.escapeshellarg($dir));
escapeshellcmd('ls $dir');
Оба делают подобные вещи и просто зависят от того, как вы справляетесь с своей логикой, убедитесь, что вы нормализуете и проверяете свой ввод, прежде чем перейти непосредственно к этим методам для лучшей безопасности.
Ответ 2
Как правило, вы захотите использовать 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 /`;
Поскольку указанный путь был использован unsanitised, любая команда может быть запущена. Мы можем использовать методы 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
делает строку безопасной для использования в качестве единственного аргумента для команды.
Ответ 3
Простое решение для определения разницы между любыми двумя аналогично звучащими функциями PHP состоит в том, чтобы написать в PHP краткую командную строку script, которая выводит все возможное пространство поиска и просто показывает различия (в этом случае сравнение 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: \ != \\
Запуск того же script под версиями 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 полностью заменяет внутренние двойные кавычки пробелами (что может быть проблемой в некоторых случаях) PHP на Linux немного отстает, чтобы избежать одиночных кавычек и обратных косых черт\экранировано\\в Windows. PHP escapeshellarg() в Windows также заменяет! И% символов пробелами. Все платформы заменяют \0 пробелами.
Обратите внимание, что поведение не обязательно согласовано между версиями PHP, и документация PHP не всегда отражает реальность. Написание быстрого script или чтение исходного кода PHP - это два способа выяснить, что происходит за кулисами.
Ответ 4
В документах PHP написано различие:
EscapeShellCmd
Следующим символам предшествует обратная косая черта: # &; `| *? ~ < > ^() [] {} $\, \ x0A и \xFF. 'и "экранируются только в том случае, если они не спарены. Windows, все эти символы плюс% заменяются пробелом.
escapeshellarg
добавляет одинарные кавычки вокруг строки и кавычки/экранирует любые существующие одинарные кавычки, позволяющие передавать строку непосредственно в оболочку и иметь его как единый безопасный аргумент.
Источник:
http://www.php.net/manual/en/function.escapeshellcmd.php
http://www.php.net/manual/en/function.escapeshellarg.php