Выполнение команд без обращений к командному интерпретатору

Проблема

Пользовательский ввод должен использоваться как часть команды, но вы не хотите, чтобы пользователь заставлял командный интерпретатор выполнять другие команды или обращаться к другим файлам. Если просто вызвать функцию system или '...' с одним аргументом (командной строкой), то для выполнения может быть использован командный интерпретатор, а это небезопасно.

Решение

В отличие от одноаргументной версии, списковый вариант функции system надежно защищен от обращений к командному интерпретатору. Если аргументы команды содержат пользовательский ввод от формы, никогда не используйте вызовы вида:
system("command $input @files");       # НЕНАДЕЖНО
Воспользуйтесь следующей записью:
system("command", $input, @files);     # НАДЕЖНЕЕ

Комментарий

Поскольку Perl разрабатывался как «язык-клей», в нем легко запустить другую программу — в некоторых ситуациях даже слишком легко.
Если вы просто пытаетесь выполнить команду оболочки без сохранения ее вывода, вызвать system в многоаргументной версии достаточно просто. Но что делать, если вы используете команду в '. . .' или она является аргументом функции open? Возникают серьезные трудности, поскольку эти конструкции в отличие от system не позволяют передавать несколько аргументов. Возможное решение — вручную создавать процессы с помощью fork и ехес. Работы прибавится, но, по крайней мере, непредвиденные обращения к командному интерпретатору не будут портить вам настроение.
Обратные апострофы используются в сценариях CGI лишь в том случае, если передаваемые аргументы генерируются внутри самой программы:
chomp($now = 'date');
Но если команда в обратных апострофах содержит пользовательский ввод — например:
@output = 'grep $input @files';
приходится действовать намного осторожнее.
die "cannot fork: $!" unless defined ($pid = open(SAFE_KID, "|-"));
if ($pid == 0) {
  exec('grep', $input, @files) or die "can't exec grep: $!";
} else {
    @output = <SAFE_KID>;
    close SAFE_KID;              # $? содержит информацию состояния
  }
Такое решение работает, поскольку ехес, как и system, допускает форму вызова, свободную от обращений к командному интерпретатору. При передаче списка интерпретатор не используется, что исключает возможные побочные эффекты.
При выполнении команды функцией open также потребуется немного потрудиться. Начнем с открытия функцией open конвейера для чтения. Вместо ненадежного кода:
open(KID_TO_READ, "$program @options @args |");    # НЕНАДЕЖНО
используется более сложный, но безопасный код:
# Добавить обработку ошибок
die "cannot fork: $!" unless defined($pid = open(KID_TO_READ, "-|"));
if ($pid) {      # Родитель
  while  (<KID_TO_READ>) {
    # Сделать что-то интересное
  }
  close(KID_TO_READ) or warn "kid exited $?";
} else {    # Потомок
    # Переконфигурировать, затем
    exec ($program, @options, @args) or die "can't exec program: $!";
  }
Безопасный конвейерный вызов open существует и для записи. Ненадежный вызов:
ореn(КID_ТО_WRIТЕ, "|$program $options @args");   # НЕНАДЕЖНО
заменяется более сложным, но безопасным кодом:
$pid = open(KID_TO_WRITE, "|-");
die "cannot fork: $!" unless defined($pid = open(KID_TO_WRITE, "|-"));
$SIG{ALRM} = sub { die "whoops, $program pipe broke" };
if ($pid) {                      # Родитель
  for (@data) { print KID_TO_WRITE $_ }
  close(KID_TO_WRITE) or warn "kid exited $?";
} else {                        # Потомок
    # Переконфигурировать, затем
    exec($program, @options, @args) or die "can't exec program: $!";
  }
Там, где комментарий гласит «Переконфигурировать», предпринимаются дополнительные меры безопасности. Вы находитесь в порожденном процессе, и вносимые изменения не распространяются на родителя. Можно изменить переменные окружения, сбросить временный идентификатор пользователя или группы, сменить каталог или маску umask и т. д.
Разумеется, все это не поможет в ситуации, когда вызов system запускает программу с другим идентификатором пользователя. Например, почтовая программа sendmail является setuid-программой, часто запускаемой из сценариев CGI. Вы должны хорошо понимать риск, связанный с запуском sendmail или любой другой setuid-программы.

См. также




2013-09-10 17:05:19

Proverte kod v komentariyah gde pro list tam oshibki detskie




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: