Как избежать случайного побега в Perl с помощью system ()? - PullRequest
0 голосов
/ 20 апреля 2010

Я хочу выполнить некоторые команды, используя команду system () , я делаю это так:

execute_command_error("trash-put '/home/$filename'");

Где execute_command_error сообщит, если произошла ошибка с какой-либо командой system, которую он выполнил. Я знаю, что могу просто отсоединить файл с помощью команд Perl, но я хочу удалить материал, используя trash-put, так как это тип программы утилизации.

Моя проблема в том, что $filename иногда будет содержать апострофы, кавычки и другие странные символы, которые портят команду system или сам Perl.

Ответы [ 2 ]

5 голосов
/ 20 апреля 2010

Создайте имя команды и аргументы в виде массива и передайте его системе:

my(@command) = ("trash-put", 'home/$filename');
system @command;

Это означает, что Perl не вызывает оболочку для выполнения какого-либо расширения метасимвола (или перенаправления ввода-вывода, или передачи команд, или ...). Это значит, что он делает именно то, что вы сказали.

sub execute_command_error
{
    system @_;
}

Заимствование информации из обильной коллекции комментариев:

Что четко задокументировано в perldoc -f system или в perldoc.perl.org / functions / system.html (@Ether).

(См. Также обсуждение «exec» ниже, которое тесно связано.)

Вы хотели поместить $ filename в одинарные кавычки? (@Mobrule).

Я намеревался использовать одинарные кавычки - я демонстрирую, что $filename не раскрывается Perl или Shell ... В моем тестовом скрипте я использовал 'my.$file', и это дало мне файл с $ в названии - как я и предполагал.

Я думаю, что желаемое цитирование, если вы действительно хотите вызвать оболочку (например, если вы хотите использовать какой-либо конвейер), это $ command_line = "\" $ command \ "\" $ arg1 \ "\" $ arg2 \ ".. . ". (@Jefromi).

Добавление двойных кавычек вокруг аргументов не поможет при использовании встроенных $, обратного ключа 1 , '$(...)' и связанных с ним обозначений. Вам более всего нужны одинарные кавычки вокруг вещей, но затем вам нужно переписать встроенные одинарные кавычки как «'\''», который генерирует одинарную кавычку для завершения текущего аргумента с одинарными кавычками, комбинацию с обратной косой чертой для представления одинарной кавычки и еще одна одиночная кавычка для возобновления аргумента в одинарных кавычках.

Это было бы хорошим решением, если бы я использовал системную команду напрямую; Тем не менее, я использую функцию webmin execute_command, которая мне не нравится, поэтому я не знаю, как ее отредактировать, чтобы учесть массивы. Не могли бы вы расширить переписывание встроенных одинарных кавычек как "'\''" ... Это то, что я сейчас буду использовать. (@ Брайан)

Грубо говоря, оболочка (Unix) обрабатывает одинарные кавычки так: «все от первой одинарной кавычки до следующей - буквальный текст, без метасимволов». Таким образом, чтобы оболочка воспринимала что-либо как буквальный текст, заключите его в один символ. Это касается всего, кроме самих одинарных кавычек. Как говорится в моем комментарии, вы должны использовать заменяющую строку из 4 символов, чтобы вставить одинарную кавычку в середину аргумента с одинарными кавычками.

Вероятно, есть более удобный способ сделать это, чем этот (возможно, с использованием одной или двух map операций), но это должно работать:

for (my $i = 0; $i < scalar(@command); $i++)
{
    $command[$i] =~ s/'/'\\''/g; # Replace single quotes by the magic sequence
    $command[$i] = "'$command[$i]'"; # Wrap value in single quotes
}

Затем вы можете присоединиться к массиву, чтобы сделать одну строку для передачи execute_command.


Лучше написать это как system {$ command [0]} @command для обработки случая, когда @command имеет один элемент. Это одна из вещей, о которой я говорю в главе «Методы безопасного программирования» Мастеринг Perl . (@Briandfoy).

Как правило, я приму это исправление. Я не уверен, что это важно в данном случае, хотя, где имя команды предоставляется программой, и только аргументы могут быть предоставлены пользователю. Имя команды 'trash-put' защищено от расширений оболочки (IFS сбрасывается оболочкой по умолчанию при запуске, поэтому путь атаки недоступен).

Эта проблема обсуждается на справочной странице 'perldoc -f exec' :

Если вы на самом деле не хотите выполнять первый аргумент, но хотите лгать программе, которую вы выполняете, относительно ее собственного имени, вы можете указать программу, которую вы на самом деле хотите запустить, как «косвенный объект» (без запятая) перед списком. (Это всегда вызывает интерпретацию LIST как многозначного списка, даже если в списке только один скаляр.)

Пример:

   $shell = '/bin/csh';
   exec $shell '-sh'; # pretend it's a login shell

или, точнее,

   exec {'/bin/csh'} '-sh'; # pretend it's a login shell

Когда аргументы выполняются через системную оболочку, результаты зависят от ее особенностей и возможностей. Смотрите "STRING" в perlop для деталей.

Использование косвенного объекта в exec или system также более безопасно. Такое использование (которое также хорошо работает с system ()) вызывает интерпретацию аргументов как многозначного списка, даже если список имел только один аргумент. Таким образом вы будете защищены от расширения оболочки или разделения слов с пробелами в них.

   @args = ( "echo surprise" );
   exec @args;              # subject to shell escapes
                            # if @args == 1
   exec { $args[0] } @args; # safe even with one-arg list

Первая версия, без косвенного объекта, запускала программу echo, передавая ей «неожиданный» аргумент. Вторая версия не сделала; он попытался запустить программу с именем «эхо-сюрприз», не нашел ее и установил $? к ненулевому значению, указывающему на ошибку.


1 Как получить обратный тик для отображения в Markdown?

2 голосов
/ 20 апреля 2010

Как указано в perldoc -f system :

Если в LIST более одного аргумента или если LIST является массивом с более чем одним значением запускает программу, заданную первым элементом списка, с аргументами, заданными остальной частью списка. Если есть только один скалярный аргумент , аргумент проверяется на наличие метасимволов оболочки, и, если они есть, весь аргумент передается системе командная оболочка для разбора (это "/ bin / sh -c" на платформах Unix, но отличается на других платформах). Если в оболочке нет метасимволов аргумент, он разбит на слова и передан непосредственно в "execvp", что более эффективно.

Мне нравится использовать IPC :: System :: Simple версию system (), которая дает больше контроля, например, возможность захватывать различные исключения и обрабатывать определенные коды ошибок как «плохие» и другие как "хорошие":

use IPC::System::Simple qw(system);
system("cat *.txt");   # will die on failure
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...