![]() |
Sql-инъекции: борьба в удовольствие
Опасность SQL-инъекций зачастую недооценивают. А даже если и знают в них толк, то нередко оставляют мероприятия по защите «на потом». И напрасно, поскольку существует довольно простой способ защиты. Этот способ, помимо собственно защиты, позволяет чрезвычайно удобно собирать тексты SQL-запросов из констант и переменных, не прибегая ни к утомительной работе с одинарными и двойными кавычками, ни к объектным способам доступа к БД.
Если скрипты уже написаны, то ничего не стоит изменить в них глобальной автозаменой всего одну функцию (обратная совместимость сохраняется). Но лучше всё же использовать приведённую методику с самого начала, тем более. Что она ещё и существенно упрощает отладку кода. В чём опасность? SQL-инъекция - один из распространённых способов взлома сайтов, позволяющий злоумышленнику исполнить практически любой SQL-запрос. Например, если URL страницы имеет вид http://life.screenshots.ru/index.php?login=vasja то вместо vasja можно написать нечто вроде Код:
vasja'; DELETE FROM SomeTable --PHP код:
Код:
SELECT * FROM WebsiteUsers WHERE ID='vasja'; DELETE FROM SomeTable --‘Подробнее можно почитать на Wikipedia или любых хакерских сайтах. Как люди борются? Есть несколько типовых вариантов борьбы с инъекциями вредоносного кода. Простейший - стандартная функция mysql_escape_string и подобные ей, которые заэскейпливают символы-разделители вроде точки с запятой, кавычки и т.п. Но такой метод не спасает от вставки всяких управляющих слов вроде OR, AND и т.п. Более того, нет гарантии, что ваш сервер БД поддерживает эскейп-последовательности символов. Второй способ заключается в отлавливании известных вариантов инъекций, например, тех же слов OR и AND. Но, во-первых, иногда требуется передать запросу как раз такую последовательность в штатном режиме (а отключать в таких случаях защиту - ещё больший повод для путаницы). А, во-вторых, перебирать сотню вариантов - тупиковый путь, поскольку всегда найдётся сто первый. Третий способ - это использование объектных «обёрток», когда параметры запроса «скармливаются» объекту при помощи присваивания значений свойствам или вызовов отдельных методов. Этот путь хорош всем, за исключением его громоздкости (а классы работы с БД почти всегда слоноподобны). Есть способ лучше Собственно, основная проблема SQL, которая приводит к возможности SQL-инъекций, заключается в отсутствии контроля типов передаваемых значений параметров запроса. Поэтому решение очевидно - параметры нужно предварительно типизировать! Мы предлагаем использовать одну-единственную короткую и несложную функцию, которой нужно заменить вызовы mysql_query. В принципе, вам не составит труда написать её самостоятельно, но свои варианты на PHP и ASP мы написали довольно давно и за время эксплуатации добавили немало удобств и поисправляли ошибок. Формат вызова: PHP код:
Сама строка шаблона - это обычная строка запроса, в которой, однако, в местах, где требуется вставить значение параметра, стоят специальные маркеры. Например: PHP код:
PHP код:
Процедура проанализирует типы переданных параметров (поскольку и в PHP, и в JScript есть возможность доступа к переданным функции параметрам как к элементам предопределённого массива, мы можем указывать любое количество параметров). Для первого тип будет приведён к числовому (и вставить управляющие символы или слова будет невозможно). Для второго просто будут заэскейплены (либо заменены на другие - зависит от диалекта SQL) кавычки, которые могли бы разорвать текст запроса, а также добавлены кавычки, обрамляющие полученную строковую константу. Полученная в итоге безопасная SQL-строка будет передана на обработку mysql_query. Собственно, вот и вся идея. А дальше начинается хронический улучшай. Поддержка нескольких соединений В JScript, например, очень удобно сделать два синтаксиса: PHP код:
PHP код:
Поддержка префиксации таблиц Нередка ситуация, когда необходимо в одной физической БД хранить таблицы, которые, по-хорошему, должны бы принадлежать разным БД. Например, это актуально, если хостинг-провайдер предоставляет ограниченное число БД (и требует деньги за возможность создания дополнительных БД). Или же иногда возникает возможность сделать один запрос к двум таблицам, принадлежащим разным БД – и сделать это технически непросто. Поэтому большинство тиражируемых web-приложений (например, блоговый «движок» Wordpress) при установке запрашивает, какой префикс дописать к идентификаторам всех своих таблиц БД - и становится возможным установить на одной БД сколько угодно таких движков. Решение снова лежит на поверхности. Вводим новый маркер ^@ и ещё один глобальный параметр сайта (напомним - первый был объектом соединения с БД) - префикс таблицы: PHP код:
PHP код:
Поддержка отладки Очень удобно, когда вы можете увидеть подробную отладочную информацию, включая собранный текст SQL-запроса, который потом можно вставить в консоль сервера. Для этого достаточно ввести ещё один глобальный параметр (opt_debug_mode, а для PHP-реализации ещё и opt_debug_show_sql, в котором разрешать либо запрещать вывод на поток отладочной информации. Поддержка дополнительных типов Ничто не мешает добавить обработку дополнительных типов параметров (нам мешает нехватка времени - но как-нибудь обязательно надо будет сделать, а пока опишем идеи). Помимо этого, можно ввести дополнительные ограничения типов, например, ^S[50], которое будет автоматически обрезать строковой параметр до длины в 50 символов (согласитесь, это удобнее, чем обрезать отдельным substr). Подобным же образом (^D, ^D[hh-MM-yyyy] - в каком формате подаётся значение параметра) можно автоматизировать весьма утомительную работу с датами/временем. При помощи ^0 можно удобно трансформировать значения переменных null, undefined и т.п. в IS NULL или IS NOT NULL При помощи ^M[regexp] можно контролировать соответствие входного строкового параметра самым сложным правилам - тогда xquery будет возвращать false в случае несоответствия. Ну, наверное, идею вы поняли. Где взять исходники? Нашими исходниками вы можете пользоваться по своему усмотрению, не забывая на нас ссылаться. Если у вас есть идеи по улучшению и исправлению, то присылайте их нам - будем весьма признательны. В настоящее время PHP- и JScript-версии несколько различаются по функциональности, но мы надеемся, что через некоторое время их уравняем. • Исходник xquery на JScript (IIS ASP) для MS SQLServer • Исходник xquery на PHP для mySQL Взято из life.screenshots.ru |
| Время: 14:38 |