Суббота , 20 Апрель 2024
ДомойБезопасностьобработка пользовательских переменных, sql-инъекция

обработка пользовательских переменных, sql-инъекция

php

в предыдущих статьях говорилось о php-инъекции и xss. здесь будет рассказано о не менее страшной уязвимости, называемой sql-инъекция, с помощью которой можно получить содержимое всех баз и таблиц, доступных текущему mysql-пользователю.

sql-инъекция

здесь дело также в недостаточной фильтрации, а иногда от недопонимания принципа работы sql.

$id   = $_GET['id'];
$pass = $_GET['pass'];
$q = "SELECT * FROM `table` WHERE `id` = $id AND `pass` = '$pass'";
$id = addslashes($_GET['id']);
$q = "SELECT * FROM `table` WHERE `id` = $id";

вариант из первой строки просто кричит о sql-инъекции. в самом деле, подставив с адресной строке браузера такой запрос:

http://site.ru/?id=1+--+

можно запросто авторизоваться хоть под администратором: поле pass обрабатываться не будет, т. к. оно закомментировано (в sql 2 знака минус с последующим пробелом означают комментарий до конца строки).

но вот в 4 строке вроде бы данные обрабатываются. только происходит совсем не то, что думает программист. достаточно передать такой параметр, чтобы убедиться в баге скрипта:

http://site.ru/?id=0+UNION+SELECT+1,2,3,4

в зависимости от того, сколько полей в выборке, второй select легко дополнить/урезать нужным количеством чисел, разделённых запятой. т. е. может понадобится передать SELECT+1,2,3,4,5,6. это в любом случае не проблема: пробежавшись по значениям, допустим, до 20, злоумышленник найдёт нужное. и после этого получит всё, что душе угодно. как? да элементарно. с 5 версии mysql содержит содержит специальную базу information_schema, в которой есть таблица TABLES. вот из неё-то и можно легко получить все значения баз данных/таблиц, доступных текущему пользователю.

вложенный select нужно передать в том параметре, который участвует в выводе на экран. какой это параметр узнали из предыдущего запроса (когда передавали 1,2,3,4; какая цифра в браузере отобразилась, заместо той вложенная выборка и ставится). и пусть идёт получение 1 параметра, ничего не стоит написать небольшой скрипт на php, в котором «зациклить» значения получаемых смещений:
LIMIT+0,1 LIMIT+1,1 LIMIT+2,1
и т. д., пока не закончатся базы.

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

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

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

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

так как же не допустить утечки информации? если в запросе ожидается целое значение, то проще поступившую переменную привести к данному типу. если ожидается строковое представление, то значение обязательно должно быть обработано специальной функцией, а в запросе — заключено в кавычки:

$id   = (int) $_GET['id'];
$pass = mysql_real_escape_string($_GET['pass']);
$q = "SELECT * FROM `table` WHERE `id` = $id AND `pass` = '$pass'";

зачем нужна специальная функция, понятно из описаний:

addslashes — заслэшивает кавычку ‘, двойную кавычку " и NUL-символ;
mysql_real_escape_string — помимо кавычки, двойной кавычки и NUL экранированию подвергаются переводы строк: \r и \n, обратная косая черта \ и символ с кодом x1a.

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

а для обычного текста в однобайтной кодировке, или же многобайтной UTF-8 из символов с кодами x00–x1f нужны только \r (x0d), \n (x0a) и в некоторых случаях \t (x09) — всё остальное логично безжалостно вырезать.

1. несмотря на то, что код, выводимый в браузер пользователя, формируется скриптом, кто-то может подсмотреть адрес и составить свой запрос. нельзя доверять никаким данным, пришедшим от пользователя;

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

Рейтинг: 0

Автор публикации

2 070
не в сети 12 месяцев

x64 (aka andi)

Комментарии: 2893Публикации: 405Регистрация: 02-04-2009
Так себеНеплохоХорошоЗамечательноСупер! (Оценок пока нет)
Загрузка...

Оставить комментарий

Политика конфиденциальности

Наш сайт использует файлы cookies, чтобы улучшить работу и повысить эффективность сайта. Продолжая работу с сайтом, вы соглашаетесь с использованием нами cookies и политикой конфиденциальности.

Принять