Приемы безопасного программирования веб-приложений на PHP.

Данная статья не претендует на роль всеобъемлющего руководства на тему “как сделать так, чтоб меня никто не поломал”. Так не бывает. Единственная цель этой статьи - показать некоторые используемые мной приемы для защиты веб-приложений типа WWW-чатов, гостевых книг, веб-форумов и других приложений подобного рода. Итак, давайте рассмотрим некоторые приемы программирования на примере некоей гостевой книги, написанной на PHP.

Первой заповедью веб-программиста, желающего написать более-менее защищенное веб-приложение, должно стать “Никогда не верь данным, присылаемым тебе пользователем”. Пользователи - это по определению такие злобные хакеры, которые только и ищут момента, как бы напихать в формы ввода всякую дрянь типа PHP, JavaScript, SSI, вызовов своих жутко хакерских скриптов и тому подобных ужасных вещей. Поэтому первое, что необходимо сделать - это жесточайшим образом отфильтровать все данные, присланные пользователем.

Допустим, у нас в гостевой книге существует 3 формы ввода: имя пользователя, его e-mail и само по себе тело сообщения. Прежде всего, ограничим количество данных, передаваемых из форм ввода чем-нибудь вроде:
<input type=text name=username maxlength=20>

На роль настоящей защиты, конечно, это претендовать не может - единственное назначение этого элемента - ограничить пользователя от случайного ввода имени длиннее 20-ти символов. А для того, чтобы у пользователя не возникло искушения скачать документ с формами ввода и подправить параметр maxlength, установим где-нибудь в самом начале скрипта, обрабатывающего данные, проверку переменной окружения web-сервера HTTP-REFERER:
<?
$referer=getenv(”HTTP_REFERER”);
if (!ereg(”^http://www.myserver.com”)) {
echo “hacker? he-he…\n”;
exit;
}
?>

Теперь, если данные переданы не из форм документа, находящегося на сервере www.myserver.com, хацкеру будет выдано деморализующее сообщение. На самом деле, и это тоже не может служить 100%-ой гарантией того, что данные ДЕЙСТВИТЕЛЬНО переданы из нашего документа. В конце концов, переменная HTTP_REFERER формируется браузером, и никто не может помешать хакеру подправить код браузера, или просто зайти телнетом на 80-ый порт и сформировать свой запрос. Так что подобная защита годится только от Ну Совсем Необразованных хакеров. Впрочем, по моим наблюдениям, около 80% процентов злоумышленников на этом этапе останавливаются и дальше не лезут - то ли IQ не позволяет, то ли просто лень. Лично я попросту вынес этот фрагмент кода в отдельный файл, и вызываю его отовсюду, откуда это возможно. Времени на обращение к переменной уходит немного - а береженого Бог бережет.

Следующим этапом станет пресловутая жесткая фильтрация переданных данных. Прежде всего, не будем доверять переменной maxlength в формах ввода и ручками порежем строку:
$username=substr($username,0,20);

Не дадим пользователю использовать пустое поле имени - просто так, чтобы не давать писать анонимные сообщения:
if (empty($username)) {
echo “invalid username”;
exit;
}

Запретим пользователю использовать в своем имени любые символы, кроме букв русского и латинского алфавита, знака “_” (подчерк), пробела и цифр:
if (preg_match(”/[^(\w)|(\x7F-\xFF)|(\s)]/”,$username)) {
echo “invalid username”;
exit;
}

Я предпочитаю везде, где нужно что-нибудь более сложное, чем проверить наличие паттерна в строке или поменять один паттерн на другой, использовать Перл-совместимые регулярные выражения (Perl-compatible Regular Expressions). То же самое можно делать и используя стандартные PHP-шные ereg() и eregi(). Я не буду приводить здесь эти примеры - это достаточно подробно описано в мануале.

Для поля ввода адреса e-mail добавим в список разрешенных символов знаки “@” и “.”, иначе пользователь не сможет корректно ввести адрес. Зато уберем русские буквы и пробел:
if (preg_match(”/[^(\w)|(\@)|(\.)]/”,$usermail)) {
echo “invalid mail”;
exit;
}

Поле ввода текста мы не будем подвергать таким жестким репрессиям - перебирать все знаки препинания, которые можно использовать, попросту лень, поэтому ограничимся использованием функций nl2br() и htmlspecialchars() - это не даст врагу понатыкать в текст сообщения html-тегов. Некоторые разработчики, наверное, скажут: “а мы все-таки очень хотим, чтобы пользователи _могли_ вставлять теги”. Если сильно неймется - можно сделать некие тегозаменители, типа “текст, окруженный звездочками, будет высвечен bold’ом.”. Но никогда не следует разрешать пользователям использование тегов, подразумевающих подключение внешних ресурсов - от тривиального <img> до супернавороченного <bgsound>.

Как-то раз меня попросили потестировать html-чат. Первым же замеченным мной багом было именно разрешение вставки картинок. Учитывая еще пару особенностей строения чата, через несколько минут у меня был файл, в котором аккуратно были перечислены IP-адреса, имена и пароли всех присутствовавших в этот момент на чате пользователей. Как? Да очень просто - чату был послан тег <img src=http://myserver.com/myscript.pl>, в результате чего браузеры всех пользователей, присутствовавших в тот момент на чате, вызвали скрипт myscript.pl с хоста myserver.com. (там не было людей, сидевших под lynx’ом :-) ). А скрипт, перед тем как выдать location на картинку, свалил мне в лог-файл половину переменных окружения - в частности QUERY_STRING, REMOTE_ADDR и других. Для каждого пользователя. С вышеупомянутым результатом.

Посему мое мнение - да, разрешить вставку html-тегов в чатах, форумах и гостевых книгах - это красиво, но игра не стоит свеч - вряд ли пользователи пойдут к Вам на книгу или в чат, зная, что их IP может стать известным первому встречному хакеру. Да и не только IP - возможности javascript’a я перечислять не буду :-)

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

Допустим, вся система модерирования книги также состоит из двух частей - страницы со списком сообщений, где можно отмечать подлежащие удалению сообщения, и непосредственно скрипта, удаляющего сообщения. Назовем их соответственно admin1.php и admin2.php.

Простейший и надежнейший способ аутентикации пользователя - размещение скриптов в директории, защищенной файлом .htaccess. Для преодоления такой защиты нужно уже не приложение ломать, а web-сервер. Что несколько сложнее и уж, во всяком случае, не укладывается в рамки темы этой статьи. Однако не всегда этот способ пригоден к употреблению - иногда бывает надо проводить авторизацию средствами самого приложения.

Первый, самый простой способ - авторизация средствами HTTP - через код 401. При виде такого кода возврата, любой нормальный браузер высветит окошко авторизации и попросит ввести логин и пароль. А в дальнейшем браузер при получении кода 401 будет пытаться подсунуть web-серверу текущие для данного realm’а логин и пароль, и только в случае неудачи потребует повторной авторизации. Пример кода для вывода требования на такую авторизацию есть во всех хрестоматиях и мануалах:
if (!isset($PHP_AUTH_USER)) {
Header(”WWW-Authenticate: Basic realm=\”My Realm\”");
Header(”HTTP/1.0 401 Unauthorized”);
exit;
}

Разместим этот кусочек кода в начале скрипта admin1.php. После его выполнения, у нас будут две установленные переменные $PHP_AUTH_USER и PHP_AUTH_PW, в которых соответственно будут лежать имя и пароль, введенные пользователем. Их можно, к примеру, проверить по SQL-базе:

*** Внимание!!!***

В приведенном ниже фрагменте кода сознательно допущена серьезная ошибка в безопасности. Попытайтесь найти ее самостоятельно.
$sql_statement=”select password from peoples where name=’$PHP_AUTH_USER’”;
$result = mysql($dbname, $sql_statement);
$rpassword = mysql_result($result,0,’password’);
$sql_statement = “select password(’$PHP_AUTH_PW’)”;
$result = mysql($dbname, $sql_statement);
$password = mysql_result($result,0);
if ($password != $rpassword) {
Header(”HTTP/1.0 401 Auth Required”);
Header(”WWW-authenticate: basic realm=\”My Realm\”");
exit;
}

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

Итак, раскрываю секрет: допустим, хакер вводит заведомо несуществующее имя пользователя и пустой пароль. При этом в результате выборки из базы переменная $rpassword принимает пустое значение. А алгоритм шифрования паролей при помощи функции СУБД MySQL Password(), так же, впрочем, как и стандартный алгоритм Unix, при попытке шифрования пустого пароля возвращает пустое значение. В итоге - $password == $rpassword, условие выполняется и взломщик получает доступ к защищенной части приложения. Лечится это либо запрещением пустых паролей, либо, на мой взгляд, более правильный путь - вставкой следующего фрагмента кода:
if (mysql_numrows($result) != 1) {
Header(”HTTP/1.0 401 Auth Required”);
Header(”WWW-authenticate: basic realm=\”My Realm\”");
exit;
}

То есть - проверкой наличия одного и только одного пользователя в базе. Ни больше, ни меньше.

Точно такую же проверку на авторизацию стоит встроить и в скрипт admin2.php. По идее, если пользователь хороший человек - то он приходит к admin2.php через admin1.php, а значит, уже является авторизованным и никаких повторных вопросов ему не будет - браузер втихомолку передаст пароль. Если же нет - ну, тогда и поругаться не грех. Скажем, вывести ту же фразу “hacker? he-he…”.

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

Пользователь один раз авторизуется при помощи веб-формы и скрипта, который проверяет правильность имени и пароля.

Остальные скрипты защищенной части приложения каким-нибудь образом проверяют факт авторизованности пользователя.

Такая модель называется сессионной - после прохождения авторизации открывается так называемая “сессия”, в течение которой пользователь имеет доступ к защищенной части системы. Сессия закрылась - доступ закрывается. На этом принципе, в частности, строится большинство www-чатов: пользователь может получить доступ к чату только после того, как пройдет процедуру входа. Основная сложность данной схемы заключается в том, что все скрипты защищенной части приложения каким-то образом должны знать о том, что пользователь, посылающий данные, успешно авторизовался.

Рассмотрим несколько вариантов, как это можно сделать:

После авторизации все скрипты защищенной части вызываются с неким флажком вида adminmode=1. (Не надо смеяться - я сам такое видел).

Ясно, что любой, кому известен флажок adminmode, может сам сформировать URL и зайти в режиме администрирования. Кроме того - нет возможности отличить одного пользователя от другого.

Скрипт авторизации может каким-нибудь образом передать имя пользователя другим скриптам. Распространено во многих www-чатах - для того, чтобы отличить, где чье сообщение идет, рядом с формой типа text для ввода сообщения, пристраивается форма типа hidden, где указывается имя пользователя. Тоже ненадежно, потому что хакер может скачать документ с формой к себе на диск и поменять значение формы hidden. Некоторую пользу здесь может принести вышеупомянутая проверка HTTP_REFERER - но, как я уже говорил, никаких гарантий она не дает.

Определение пользователя по IP-адресу. В этом случае, после прохождения авторизации, где-нибудь в локальной базе данных (sql, dbm, да хоть в txt-файле) сохраняется текущий IP пользователя, а все скрипты защищенной части смотрят в переменную REMOTE_ADDR и проверяют, есть ли такой адрес в базе. Если есть - значит, авторизация была, если нет - “hacker? he-he…” :-)

Это более надежный способ - не пройти авторизацию и получить доступ удастся лишь в том случае, если с того же IP сидит другой пользователь, успешно авторизовавшийся. Однако, учитывая распространенность прокси-серверов и IP-Masquerad’инга - это вполне реально.

Единственным, известным мне простым и достаточно надежным способом верификации личности пользователя является авторизация при помощи random uid. Рассмотрим ее более подробно.

После авторизации пользователя скрипт, проведший авторизацию, генерирует достаточно длинное случайное число:
mt_srand((double)microtime()*1000000);
$uid=mt_rand(1,1000000);

Это число он:
заносит в локальный список авторизовавшихся пользователей;
Выдает пользователю.

Пользователь при каждом запросе, помимо другой информации (сообщение в чате, или список сообщений в гостевой книге), отправляет серверу свой uid. При этом в документе с формами ввода будет присутствовать, наряду с другими формами, тег вида:
<input type=hidden name=uid value=1234567890>

Форма uid невидима для пользователя, но она передается скрипту защищенной части приложения. Тот сличает переданный ему uid с uid’ом, хранящимся в локальной базе и либо выполняет свою функцию, либо… “hacker? he-he…”.

Единственное, что необходимо сделать при такой организации - периодически чистить локальный список uid’ов и/или сделать для пользователя кнопку “выход”, при нажатии на которую локальный uid пользователя сотрется из базы на сервере - сессия закрыта.

Некоторые программисты используют в качестве uid не “одноразовое” динамически генерирующееся число, а пароль пользователя. Это допустимо, но это является “дурным тоном”, поскольку пароль пользователя обычно не меняется от сессии к сессии, а значит - хакер сможет сам открывать сессии. Та же самая модель может быть использована везде, где требуется идентификация пользователя - в чатах, веб-конференциях, электронных магазинах.

В заключение стоит упомянуть и о такой полезной вещи, как ведение логов. Если в каждую из описанных процедур встроить возможность занесения события в лог-файл с указанием IP-адреса потенциального злоумышленника - то в случае реальной атаки вычислить хакера будет гораздо проще, поскольку хакеры обычно пробуют последовательно усложняющиеся атаки. Для определения IP-адреса желательно использовать не только стандартную переменную REMOTE_ADDR, но и менее известную HTTP_X_FORWARDED_FOR, которая позволяет определить IP пользователя, находящегося за прокси-сервером. Естественно - если прокси это позволяет.

При ведении лог-файлов, необходимо помнить, что доступ к ним должен быть только у Вас. Лучше всего, если они будут расположены за пределами дерева каталогов, доступного через WWW. Если нет такой возможности - создайте отдельный каталог для лог-файлов и закройте туда доступ при помощи .htaccess (Deny from all).

Я буду очень признателен, если кто-нибудь из программистов поделится своими не описанными здесь методами обеспечения безопасности при разработке приложений для Web.

Автор: Илья Басалаев

Тсточник http://www.codenet.ru

Tags: php, SQL, безопасность

Добавить комментарий Март 16, 2008

Защита сайта от SQL инъекции с помощью mod_rewrite

Не секрет, что можно взломать абсолютно любой сайт, идеальной защиты не бывает. Взломать интернет сайт, намного легче, чем взломать прикладную программу, да и делать это гораздо интереснее, ведь твои труды увидят тысячи пользователей (разумеется если взломанный сайт достаточно популярен). На сегодняшний день известно множество методик взломов интернет-сайтов, одним из самых опасных является так называемая инъекция ( Injection - введение). Инъекция бывает разной можно внедрить свой код в программу, можно внедрить инородные данные в поток чужих данных, но одной из самых опасных для интернет-сайтов является SQL инъекция ( SQL Injection ). Из названия уже становится понятно, что и куда внедряется. На всякий случай поясню, при SQL инъекции мы внедряем наш код в SQL запрос, в результате чего при благополучных обстоятельствах мы можем получить данные хранящиеся в базе данных не доступные для просмотра стандартными средствами. Многие полагают, что SQL инъекцией страдает только база данных MySQL, но это конечно же не так. SQL инъекцию можно осуществить в любую базу, поддерживающую языки запросов (а таких большинство).

Рассмотрим вышесказанное на простом примере. Рассматривать все будем на примере MySQL, так как эта БД является одной из самых популярных среди web-программистов.

Пусть у нас есть таблица в которой есть 3 поля (md,password,login). Пусть у каждого пользователя есть свой секретный код (md), например он может быть такой sdf897sdsdf87sdf99sdf87. В поле password записан пароль пользователя, а в поле login имя пользователя.

Пусть у нас есть следующий код на PHP :
$result = mysql_query ( “SELECT password FROM user_table WHERE md=?$usermd?” ); // сам запрос
$pass = mysql_result ( $result , ?? , ?password? ); //записываем в переменную $pass значение поля password
echo $pass ; // выводим переменную $pass на экран

Этот код берет из таблицы user_table значение поля password у записи, md которой равен переменной $usermd, а затем выводит этот пароль. Пусть каждый пользователь знает свой собственный md, но не знает md других пользователей, тогда очевидно, что попытка подобрать md чужого пользователя на 99% обречена на провал.

Как же можно узнать пароль другого пользователя? Оказывается можно, достаточно поместить в переменную $usermd свой код, например такой ” ? or login=?admin?# ” (подразумевается что, администратор имеет login=”admin” ). Как будет Хакер делать подмену, это вопрос другой, но факт остается фактом, в данном случае на экран выведется пароль администратора.

Давайте проанализируем, что же произошло. В результате подмены запрос принял вид:

“SELECT password FROM user_table WHERE md=?? or login=?admin?#?”

Думаю что теперь все понятно, поясню лишь, зачем нужен символ #. Все что находится после символа # обрезается, т.е. не является частью запроса, сам символ # является спецсимволом и разумеется тоже не участвует в запросе. При таком запросе база попытается выбрать запись с пустым полем md, или у которых login=?admin?, поскольку записей с пустым md не существует, то выберется запись у которой поле login равно “admin”.

Это всего лишь пример, он не претендует на звание наиярчайшего примера SQL инъекции, он лишь демонстрирует, к чему все это может привести. Не стоит считать, что такого абсурдного кода не существует, и никто не будет открыто хранить пароль администратора. SQL инъекцией страдают большинство CMS а также крупнейших Forum ?ов, в том числе и InvisionPB, не говоря уже о PhpBB и его клонах.

Все это как ни странно было всего лишь вступлением, на самом деле я не планировал рассказывать о инъекции, но как говориться “нужно знать врага в лицо”. Как же можно защитить свои скрипты, от подобной уязвимости? На самом деле очень легко, нужно всего лишь проверять входные данные. Реализовать это можно различными способами, лучший из них, это просто проверить наличие спецсимволов в переменной, и если таковые имеются занести в лог информацию о попытке взлома, вместе с IP взломщика, чтобы в последствии можно было его забанить. Второй способ более простой, можно сразу не проверяя вырезать из переменной все спецсимволы, например с помощью команды str_replace. Этот способ простой, но имеет недостаток: SQL запрос все равно будет выполнен, причем переменная будет заведомо содержать ошибочные данные, поэтому на экране может отобразиться целая гора ошибок (в зависимости от сложности скрипта).

Я хочу предложить свой способ защиты скриптов. Этот способ не является лучшим, но на мой взгляд, он очень изящен и имеет несколько плюсов, о которых я конечно же расскажу. Способ заключается в использование модуля для сервера Apache, который носит название mod_rewrite. Этот модуль установлен практически на всех платных хостингах. Задача этого модуля - изменять введенную информацию пользователя в строке URL на другую, нужную вам. Чтобы было понятнее приведу простой пример.

Допустим, пользователь введет в строке адрес http://site.ru/download.html. Этот адрес получает сервер, но только после того, как его обработает mod_rewrite (если он включен конечно). Модуль mod_rewrite анализирует введенный адрес, и согласно своим настройкам изменяет или не изменяет его. Изменить он может на что угодно, например он может отдать серверу вместо введенного адреса другой адрес например http://site.ru/article.html, в результате чего у пользователя отобразиться на экране страница article.html, хотя в строке адреса по прежнему будет отображаться http://site.ru/download.html, и пользователь даже не будет подразумевать, что его “обманули”.

Зачем же нужен этот модуль? На самом деле цель у него одна - сделать ссылки более красивыми, но использовать его можно для разных целей. Одной из них и является защита сайта от SQL инъекции.

Давайте вернемся к нашему примеру с паролем администратора и попробуем защитить наш скрипт с помощью mod_rewrite. Пусть переменная $usermd передается скрипту GET запросом: http://site.ru/script.php?usermd=4k2jhk34jhkjh6kh7kh33. Как видите в переменной $usermd будет храниться значение “4k2jhk34jhkjh6kh7kh33″, мы знаем, что эта переменная может содержать цифры от 0 до 9 и латинские буквы от a до z. Теперь давайте с помощью mod_rewrite изменим наш адрес на более красивый, а заодно и реализуем проверку на входные данные.

Для того чтобы воспользоваться модулем mod_rewrite вам необходимо создать файл .htaccess в корневом каталоге (обратите внимание на точку в начале файла). Запишите в этот файл следующие строки:

RewriteEngine on
Options +FollowSymlinks
RewriteBase /
RewriteRule ^.htaccess$ - [F]

Эти команды сообщают серверу, что необходимо использовать модуль mod_rewrite. Далее за этим кодом будут следовать правила замена адресов, общий вид которых:

RewriteRule входной_адрес на_что_заменить

Например, чтобы нам подменить адрес http://site.ru/download.html на http://site.ru/article.html необходимо написать:

RewriteRule http://site.ru/download.html http://site.ru/article.html

Как видите все просто. Но на самом деле все чуточку сложнее. Дело в том, что в данном примере мы имеем дело со статическими страницами, адрес которых никогда не измениться, если же мы имеем дело со скриптами, переменные в которых принимают разные значения, такой способ не подойдет. Для этого mod_rewrite позволяет использовать регулярные выражения. Если вы с ними не знакомы, то вам будет сложно разобраться с модулем, но все же можете попытаться. Советую вам почитать дополнительную информацию о регулярных выражениях, так как она никогда лишней не бывает.

Снова вернемся к нашему примеру. Что же нам необходимо сделать? Нам нужно заменить адрес http://site.ru/script_4k2jhk34jhkjh6kh7kh33.html на адрес http://site.ru/script.php?usermd=4k2jhk34jhkjh6kh7kh33.

Делается это следующей строкой:

RewriteRule http://site.ru/script_([a-z0-9]*).html http://site.ru/script.php?usermd=$1

Думаю нужно сделать немного пояснений. Выражение ( [a-z0-9]* ) означает, что в данном месте может находиться последовательность из цифр и букв любой длины. [a-z0-9] - перечисление допустимых символов (в данном примере заданы диапазоны), знак * означает что таких символов может быть несколько. Выражение которое соответствует маске находящейся в скобках присваивается переменной $1 (цифра обозначает номер скобок) и вставляется в адрес на который будем заменять входящий адрес.

В результате этой манипуляции после того как пользователь введет в строке адреса http://site.ru/script_4k2jhk34jhkjh6kh7kh33.html он автоматически попадет на страницу http://site.ru/script.php?usermd=4k2jhk34jhkjh6kh7kh33. И конечно же переменная $usermd будет содержать значение “4k2jhk34jhkjh6kh7kh33″.

Теперь давайте рассмотрим, что же произойдет если пользователь попытается ввести http://site.ru/script_?%20or%20login=?admin?#.html ( %20 - тоже самое что и пробел). В результате этого запроса адрес попадет модулю mod_rewrite, который проанализирует его, т.к. выражение ?%20or%20login=?admin?# не подходит под маску ( [a-z0-9]* ), т.к. содержит недопустимые символы, то mod_rewrite ничего не сделает, так как будто его вообще нет, очевидно, что в этом случае пользователю будет возвращена ошибка 404 Page not found (404 страница не найдена).

Это и есть защита. Она не идеальна и имеет минусы, но есть и плюсы. Главный минус - это то, что в скрипты, все же можно передать вредоносную информацию, но для этого придется воспользоваться методом POST, а не GET. Второй минус - mod_rewrite немного нагружает сервер, как и любые регулярные выражения. Главный плюс - пользователь не видит, как называются ваши переменные.

Ну вот собственно и все, о чем я хотел рассказать. Я показал всего лишь пример, на самом деле модуль mod_rewrite намного мощнее, собственно как SQl инъекция. И помните, идеальной защиты не существует.

Данная информация дана в ознакомительных целях, автор не несет ответственности за возможно взломанные скрипты.

Нгуен Павел http://excode.ru

Tags: htaccess, mod_rewrite, MySQL, Options, SQL

Добавить комментарий Март 4, 2008

PHP Фильтрация данных

Каждый web-мастер должен уметь не только писать скрипты, но и грамотно организовывать защиту своих творений. Одним из важнейших навыков является умение правильно фильтровать всю информацию, поступающую от пользователя. Об этом и пойдет речь в моей статье.

Прежде всего, следует фильтровать данные, которые передает пользователь осознанно - в основном, это данные различных форм. Это может быть пара логин-пароль для входа, пункт голосования и т.п. Например, такая формаДалее...

<form action=”index.php” method=”GET”>
<input type=”text” name=”login”>
<input type=”text” name “pass”>
<input type=”submit” value=”OK”>
</form>

После нажатия кнопки “OK” передаст скрипту index.php два значения - $login и $pass. Как их можно отфильтровать? Пример для переменной $login:

if($login)
{
$login = htmlspecialchars((stripslashes($login)), ENT_QUOTES);
$login = str_replace(”/”,”",$login);
$login = str_replace(”.”,”",$login);
$login = str_replace(”`”,”",$login);
}
else
{
echo “Логин не введен!”;
}

В первой строке мы проверяем существование переменной $login, если она существует - идем дальше, если нет - выводим сообщение об ошибке. Затем с помощью функции htmlspecialchars заменяем в этой переменной спецсимволы на их HTML мнемоники. То есть знак `<` меняется на `<`, `&` меняется на `&` и т.д. Функция stripslashes вырезает знак обратного слеша `\`. Далее с помощью str_replace вырезаем знак прямого слеша, точку (иногда бывает полезно) и обратную кавычку.

Если вы знакомы с регулярными выражениями, то предыдущий пример можно записать гораздо короче:

if($login)
{
if (preg_match(”/[0-9a-z_]/i”, $login))
{
// … действия над логином …
}
else
{
echo “Логин введен неверно!”;
}
}
else
{
echo “Логин не введен!”;
}

Этот фрагмент кода будет проверять введенный логин на соответствие регулярному выражению `/[0-9a-z_]/i`, которое означает: все цифры + все латинские буквы в любом регистре + знак подчеркивания. Если логин содержит другие символы, то будет показано сообщение об ошибке.

Аналогично фильтруются переменные, получаемые скриптом через URL. В движках сайтов можно встретить что-то вроде таких ссылок:

http://www.site.com/index.php?module=news

Если не фильтровать переменную $module (или $_GET[`module`], если register_globals отключен), то над сайтом могут вытворяться не очень хорошие вещи, вроде XSS. Нужно применять первый приведенный мной скрипт-чистильщик, разумеется, убрав сообщения об ошибках.

Следующее, на чем бы я хотел остановиться - это фильтрация кукисов. Думаю, что даже если вы начинающий программист, то с “плюшками” вы сталкивались, а насчет их проверки даже не задумывались. Зря! Если вы используете SQL-базы данных, то отсутствие проверки кукисов может привести к использованию хакерами SQL-injection. Так как в кукисах, в основном, мы используем определенный тип данных, например, только числа, то проверку данных можно проводить с помощью все тех же регулярных выражений. Допустим, у нас есть кукис “id”, в котором хранятся числовые данные. Его проверка:

if($_COOKIE[`id`])
{
if (preg_match(”/[0-9]/”, $_COOKIE[`id`])
{
// … действия над кукисом …
}
else
{
echo “Хм, странный кукис. Не пойдет!”;
}
}

В сети есть огромное количество документации посвященной взлому сайтов,в частности, там показаны различные случаи использования XSS и приемы обхода фильтрации. Но мы то с вами уже умеем защищаться от непрошенных гостей ;)

Автор: Ткаченко Ярослав Андреевич

Tags: php, SQL, защита

Добавить комментарий Март 1, 2008


Календарь

Май 2012
Пн Вт Ср Чт Пт Сб Вс
« Апр    
 123456
78910111213
14151617181920
21222324252627
28293031  

Записи по месяцам

Записи по рубрикам

Бегун