Выполнение команд без обращений к командному интерпретатору
Проблема
Пользовательский ввод должен использоваться как часть команды, но вы не хотите,
чтобы пользователь заставлял командный интерпретатор выполнять другие команды или обращаться
к другим файлам. Если просто вызвать функцию 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-программы.
См. также
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|