MYSTERRIA3.0

Перл. SQL injection не пройдут.

Перл - в высшей степени либеральный язык. Он с удовольствием поможет вам решить задачу быстро и элегантно, в то же время не скажет вам и слова против (особенно если вы не используете в своем коде прагму use warnings), когда вы будете писать сущий бред и постарается выполнить все ваши ошибки программирования, пока хоть сколь-нибудь представляет, как это вообще можно сделать. А теперь давайте представим, что язык с таким подходом мы используем для вэб программирования, где каждый второй будет пытаться подсунуть нам свинью в параметр запроса. Ужас, не правда ли? Здесь же нет никаких проверок на загрязенность данных и автоматического трекинга используемого контекста (строго говоря, в ПХП его по 4-ю версию не было, это Парсер отличился) и всяких таких примочек! Есть, конечно, ключ -T, но он будет вам в помощь разве что если вы в своем скрипте настойчиво мучите оболочку, что, строго говоря, в контексте вэб программирования зело не полезно и даже вредно с точки зрения потребления этим добром ресурсов на старт новых процессов. Но не все так плохо с Перлом, даже напротив, при правильном подходе перл имунен к одной из самых больших дырок в безопасности вэб-приложений - SQL-injection-ам. Инжэкшены эти - ни что иное, как подстановка в строку запроса SQL команд вместо значений параметров. При должной сноровке атакующего и недостаточной проверке подставляемых значений в скрипте злоумышленник может получить практически любую информацию из БД. Итак, что и как делать, чтобы потом не было мучительно больно: 1. Используйте для работы с базой модуль DBI DBI - это унифицированный интерфейс программирования для работы с базами данных, не зависящий непосредственно от используемой СУБД. Если вы используете исключительно совместимые со стандартом SQL запросы в своем приложении, то при смене СУБД вам понадобится всего лишь изменить драйвер при инициализации объекта-подключения. Скачать свежую версию всегда можно с CPAN. Там же находятся драйвера под всевозможные СУБД. 2. Используйте bind-variables. А вот тут начинается волшебство. Допустим у нас есть табица вида

CREATE TABLE user( id int unsigned primary key, login varchar(30), pass char(32) );

и нам нужно на странице профиля получить значение логина пользователя 2. Ссылка на профиль будет выглядеть так: http://example.com/profile.pl?uid=2 Как делать не надо:

$user_login = $dbh->selectrow_array("SELECT login FROM user WHERE id=$form{uid}"); print "User login: $user_login";

В примере значение $form{uid} - это как раз и есть значение передаваемого параметра id запроса. Почему не надо: ...придет серенький волчок и:

http://example.com/profile.pl?uid=NULL/**/UNION/**/ALL/**/SELECT/**/pass/**/FROM/**/user WHERE/**/id%3D1

Как нетрудно догадаться, волчок уйдет с хэшем пароля, а если вы храните пароли в открытом виде, что есть моветон, то того хуже, с самим паролем. Как надо делать: Во-первых можно ринуться проверять все входящие значения через REGEX, в данном случае нам подойдет такой вариант:

die "You're sneaky hacker!" unless($form{uid} =~ /^\d+$/);

Но, согласитесь, муторно так каждый раз и с каждым параметром, да и забыть можно. И забывают. А серенькие волчки этим пользуются. Поэтому предлагаю взять за правило: при возможности никогда не пользоваться интерполяцией значений непосредственно в запрос. Вместо этого делаем так:

$user_login = $dbh->selectrow_array("SELECT login FROM user WHERE id=?", undef, $form{uid}); print "User login: $user_login";

Итак, в данном случае мы используем знак вопроса вместо значения параметра id в SQL запросе. Обратите внимание, что знак вопроса не взят в кавычки, иначе он перестанет быть волшебной переменной, а превратиться в обычный литерал. Далее добавляем наши параметры списком после SQL запроса. Первый параметр резервирован и должен иметь значение undef, далее должны идти значения в том порядке, в котором у вас стоят знаки вопроса, первый знак вопроса будет заменен первым значением, второй - вторым и так далее. Дальше - больше! Оказывается bind-variables можно использовать не только с SELECT, но и с DELETE или UPDATE запросами! Общая логика остается прежней.

$dbh->do("DELETE FROM user WHERE id=?", undef, $form{uid}); $dbh->do("UPDATE user SET login=? WHERE id=?", undef, $form{login}, $form{id});

Заметьте, в UPDATE запросе подствляем сначала логин, потом ID, потому как вопросик, относящийся к логину будет заменен первым. В заключение пример того, как можно быстро добавить экземпляр в таблицу, используя bind-variables:

 # мы знаем, какие именно поля формы надо сохранять, # в дальнейшем, если в таблицу добавится еще одно поле, надо будет добавить его # только в эту строку. Остальные строки кода останутся неизменны. my @flds = qw/id, login, pass/; # cформируем список полей для запроса, не забыв заэскейпить my $flds = join ',' map{"`$_`"}@flds; # нам понадобится столько вопросиков, сколько полей. my $qs = join ',', map{'?'}@flds; # Оппа! $dbh->do("INSERT INTO user ($flds) VALUES($qs)", undef, map{$form{$_}}@flds); 

При всей простоте и элегантности, это еще и абсолютно безопасно. Даже если какие-то из полей будут противоречить схеме таблицы, строка просто напросто не добавится. Вызывать ли при этом исключительную ситуацию - на ваше усмотрение, смотрите описание параметров метода DBI->connect().

Рубрики: Perl

↑ Наверх


blog comments powered by Disqus

Контакты

Igor Zinkovsky aka TLoD,Snake. Писать на электропочту, стучаться в аську 302380533, искать в Санкт-Петербурге.

© 2002-2019