В чем разница между escapeshellarg и escapeshellcmd?

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