Защита сайта от 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 на другую, нужную вам. Чтобы было понятнее приведу простой пример. Допустим, пользователь введет в строке адрес //site.ru/download.html. Этот адрес получает сервер, но только после того, как его обработает mod_rewrite (если он включен конечно). Модуль mod_rewrite анализирует введенный адрес, и согласно своим настройкам изменяет или не изменяет его. Изменить он может на что угодно, например он может отдать серверу вместо введенного адреса другой адрес например //site.ru/article.html, в результате чего у пользователя отобразиться на экране страница article.html, хотя в строке адреса по прежнему будет отображаться //site.ru/download.html, и пользователь даже не будет подразумевать, что его "обманули". Зачем же нужен этот модуль? На самом деле цель у него одна - сделать ссылки более красивыми, но использовать его можно для разных целей. Одной из них и является защита сайта от SQL инъекции. Давайте вернемся к нашему примеру с паролем администратора и попробуем защитить наш скрипт с помощью mod_rewrite. Пусть переменная $usermd передается скрипту GET запросом: //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 входной_адрес на_что_заменить Например, чтобы нам подменить адрес //site.ru/download.html на //site.ru/article.html необходимо написать: RewriteRule //site.ru/download.html //site.ru/article.html Как видите все просто. Но на самом деле все чуточку сложнее. Дело в том, что в данном примере мы имеем дело со статическими страницами, адрес которых никогда не измениться, если же мы имеем дело со скриптами, переменные в которых принимают разные значения, такой способ не подойдет. Для этого mod_rewrite позволяет использовать регулярные выражения. Если вы с ними не знакомы, то вам будет сложно разобраться с модулем, но все же можете попытаться. Советую вам почитать дополнительную информацию о регулярных выражениях, так как она никогда лишней не бывает. Снова вернемся к нашему примеру. Что же нам необходимо сделать? Нам нужно заменить адрес //site.ru/script_4k2jhk34jhkjh6kh7kh33.html на адрес //site.ru/script.php?usermd=4k2jhk34jhkjh6kh7kh33. Делается это следующей строкой: RewriteRule //site.ru/script_([a-z0-9]*).html //site.ru/script.php?usermd=$1 Думаю нужно сделать немного пояснений. Выражение ([a-z0-9]*) означает, что в данном месте может находиться последовательность из цифр и букв любой длины. [a-z0-9] - перечисление допустимых символов (в данном примере заданы диапазоны), знак * означает что таких символов может быть несколько. Выражение которое соответствует маске находящейся в скобках присваивается переменной $1 (цифра обозначает номер скобок) и вставляется в адрес на который будем заменять входящий адрес. В результате этой манипуляции после того как пользователь введет в строке адреса //site.ru/script_4k2jhk34jhkjh6kh7kh33.html он автоматически попадет на страницу //site.ru/script.php?usermd=4k2jhk34jhkjh6kh7kh33. И конечно же переменная $usermd будет содержать значение "4k2jhk34jhkjh6kh7kh33". Теперь давайте рассмотрим, что же произойдет если пользователь попытается ввести //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 инъекция. И помните, идеальной защиты не существует. Данная информация дана в ознакомительных целях, автор не несет ответственности за возможно взломанные скрипты. Автор: Нгуен Павел (LedWorm) - администратор проекта www.excode.ruї Блог автора: blog.excode.ruї Оригинал статьи: //blog.excode.ru/post13-protect_site_sql_injection_mod_rewrite.htmlї |