Выбрать главу

Конечно, крупные on-line магазины, как правило, не содержат грубых ошибок. Но в сети огромное количество мелких поставщиков различного рода услуг, зачастую снабженных программным обеспечением, созданным «на коленках» Дядей Васей! Ошибки, описанные выше, очень характерны для кустарных разработок.

Врезка «информация»

Огромную опасность представляют недокументированные (или плохо документированные и малоизвестные) особенности интерпретаторов. И Perl в этом смысле не является исключением.

С его реализацией на платформе PC связан один громкий скандал. Фирма “Netscape” по некоторым причинам не поддержала в своем сервере ассоциации файловых расширений с исполняемыми приложениями. Вместо этого она предложила «волшебное» решение: вручную указывать требуемое приложение в самом URL. Так, например, вызвать “hello.pl” приходилось так: http://NetscapeServer/cgi-bin/perl.exe?hello.pl.

С первого взгляда ничем, кроме недовольного ворчания WEB-мастеров, это не чревато. Но уже беглое изучение документации по PC-версии Perl доказывает обратное. Особенность обработки командой строки приводит к тому, что на сервере может быть исполнена любая команда от имени интерпретатора. Достаточно воспользоваться конвейером, то есть конструкцией вида “| команда”.

Например, если набрать в командой строке “perl xxx|dir”, где ‘xxx’ имя любого, даже не обязательно существующего, скрипта, произойдет следующее: сперва, интерпретатором будет предпринята попытка запустить файл ‘xxx’, затем, независимо от успешности предыдущей операции, будет выполнена команда ‘dir’.

Врезка «замечание»

Выполнить любую команду Perl, например, ‘exec’ можно с помощью ключа командной строки, ‘-e’, о чем сообщается даже в короткой справке, выдаваемой при указании ключа ‘-h’ в командной строке.

Ниже приведен пример (на диске, прилагаемом к книге, он находится в файлах “/SRC/form.htm” и “/SRC/form.pl”) импровизированного виртуального магазина, занимающегося продажей товара через Internet c оплатой по кредитным карточкам. Перед первой покупкой посетителю (как это заведено в большинстве систем электронной торговли) необходимо зарегистрироваться - ввести свое имя и номер кредитной карты. Здесь не будет обсуждаться вопрос контроля достоверности представленной информации (это тема для отдельного разговора). Скрипт просто запоминает введенные сведения, и сверят всякий раз при загрузке.

· «HTML» · «HEAD» · «TITLE»VIRTUAL SHOP's "Hamburg"«/title» · «META charset=windows-1251» · «/HEAD» · · «BODY» · «H1»«CENTER»VIRTUAL SHOP's "«U»Hamburg«/U»"«/CENTER» · «HR» · «/H1» · «CENTER» · «form method="POST" action="form.pl"» · «br»Name: · «BR» · «input type="text" size="30" maxlength="300" name="name" value="Vasia"» · «BR» · «br»Credit card number: · «BR» · «input type="text" size="30" maxlength="30" name="card" value="OC271191"» · «BR» · «BR» · «input type="submit" value="Welcome"» · «/form» · «/div» · «HR» · «/body» · · «/html» · · #!/usr/local/bin/perl · print "Content-type: text/html\n\n"; · print "«HEAD» «title»VIRTUAL SHOPs 'Hamburg'«/title»«/head»\n"; · print "«BODY» «H1»«CENTER»VIRTUAL SHOPs '«U»Hamburg«/U»'«/H1»«/CENTER»«HR»«BR»\n"; · · parseparameters(); · $Name=$parameters{'name'}; · $Card=$parameters{'card'}; · $Passwd="None"; · $file="users.dat"; · · open(F,"«$file") || die "File $file not exist!\n"; · · while($f=«F») · { · $tmp=«F»; · if ("$Name\n"=~$f) · { · if ($tmp!~$Card) · { · print "«CENTER»«H1»Wrong Card Number«/H1»«HR»"; · die; ·} · · $Passwd=$tmp; ·} ·} · · if ($Passwd=~/None/) · { · open(F,"»$file"); · print F "$Name\n"; · print F "$Card\n"; · close(F); · print "«B»New Buyer!«/B»«BR»\n"; ·} · · print «EOF; · Buyer:$Name · «BR» · Card:$Card · «TABLE width=100% border=1» · «TR» · «TH»Product ID · «TH»Product Name · «TH»Purchase · «TR» · «TD»Y2ZA · «TD»Mice · «TD»1 dollar · «TR» · «TD»ZG6T · «TD»Mice Pad · «TD»5 dollar · «TR» · «TD»3 FZ9Y · «TD»CD-ROM RACK · «TD»7 dollar · «/table» · «HR» · «CENTER» · «form method="POST" action="buy.pl"» · Product ID: · «input type="text" size="30" maxlength="30" name="$Name"; value="Y2ZA"» · «input type="submit" value="Buy"» · «/form» · EOF · · · · sub parseparameters(;$) { · local $_ = shift || $ENV{"REQUEST_METHOD"}; · my $buffer; · · $buffer = $ENV{"QUERY_STRING"} if (/^[Gg][Ee][Tt]$/); · read(STDIN, $buffer, $ENV{"CONTENT_LENGTH"}) if (/^[Pp][Oo][Ss][Tt]$/); · · @_ = split(/ amp;/, $buffer); · for (@_) { · tr/+/ /; · s/%(…)/pack("c",hex($1))/ge; · (my $key, my $value) = split(/=/, $_); · $parameters{lc($key)} = $value; ·} ·} ·

Если ввести имя пользователя и код кредитной карточки [302] (например, “Kris Kaspersky; oc674-ui56”) и нажать кнопку “Welcome”, то сервер поприветствует нового покупателя и предложит ввести код товара для покупки. На первый взгляд все работает нормально…

Рисунок 025 Импровизированный виртуальный магазин

Для того чтобы совершить покупку от чужого имени требуется знать номер кредитной карточки, который известен только ее обладателю. Но в данном случае сервер хранит информацию обо всех посетивших его пользователях, и существует возможность «подсунуть» чужое имя взамен своего. Для изучения содержимого странички, необходимо выбрать в меню браузера пункт «Просмотри в виде HTML»

Рисунок 026 Просмотр содержимого странички в виде HTML

Появится следующий код, содержащий, по крайней мере, одну грубейшую ошибку, которая позволяет осуществлять покупки от имени чужих лиц.

· «TH»Product ID · «TH»Product Name · «TH»Purchase · «TR» · «TD»Y2ZA · «TD»Mice · «TD»1 dollar · «TR» · «TD»ZG6T · «TD»Mice Pad · «TD»5 dollar · «TR» · «TD»3 FZ9Y · «TD»CD-ROM RACK · «TD»7 dollar · «/table» · «HR» · «CENTER» · «form method="POST" action=" buy.pl "» · Product ID: · «input type="text" size="30" maxlength="30" · name="Fox"; value="Y2ZA"» · «input type="submit" value="Buy"» · «/form»

Алгоритм работы магазина в общих чертах следующий: при нажатии на кнопку «Buy» вызывается скрипт “buy.pl”, которому передаются два параметра - имя пользователя и код покупаемого товара. А номер кредитной карточки в передаваемых параметрах отсутствует. Очевидно, скрипт “buy.pl” самостоятельно извлекает его из базы, используя имя покупателя. Поскольку пользователь не может модифицировать файлы, хранящиеся на сервере, такая схема защиты на первый взгляд кажется вполне надежной. Но что мешает злоумышленнику сохранить страничку на свой локальный диск и, отредактировав по своему желанию, запустить ее оттуда?

Чтобы не нарушить работоспособности скрипта, необходимо все относительные ссылки заменить абсолютными, то есть с полным указанием протокола, имени узла и пути к файлу. Исправленный вариант может выглядеть так (на диске, прилагаемом к книге, он находится в файле “/SRC/form_hack.htm)