Что такое sql injection java
Перейти к содержимому

Что такое sql injection java

  • автор:

Защита от SQL инъекций в jdbc java

Часто вижу утверждения, что надо использовать PreparedStatement вместо обычного Statement , чтобы защититься от sql инъекций. Как он защищает?

Отслеживать
20.2k 6 6 золотых знаков 37 37 серебряных знаков 81 81 бронзовый знак
задан 4 дек 2017 в 19:56
4,912 2 2 золотых знака 12 12 серебряных знаков 29 29 бронзовых знаков

Только нужно помнить, что подготовленные запросы, кроме вашего кода, проходят еще и через сторонний (библиотеки и jdbc-драйверы). И если в этом стороннем коде подготовленные запросы реализованы через обычные (все собирается обратно в строку), то защиты от SQL инъекций не будет. Это довольно известная проблема в мире PHP PDO.

6 апр 2018 в 9:43

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Коротко, для нетерпеливых:

При использовании Statement строки запроса и значений складываются.

При использовании PreparedStatement имеется шаблон запроса и данные в него вставляются, с отражением кавычек.

Ниже подробнее с примерами.

Вступление.

Имеем такую простую таблицу с данными.

+-----------+----+--------+ | userName | id | pass | +-----------+----+--------+ | admin | 1 | admin | | user | 2 | pass | | chuchelo | 3 | elli | +-----------+----+--------+ 

Модель User , будет содержать имя и пароль, а так же метод логин, который спросит данные с консоли.

class UserLogin < String name; String pass; public UserLogin() < >public void login() < BufferedReader reader = null; try< reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("user name: "); name = reader.readLine(); System.out.println("pass: "); pass = reader.readLine(); >catch (IOException e) < e.printStackTrace(); >finally < if (reader != null) try < reader.close(); >catch (IOException e) < e.printStackTrace(); >> > 

Метод, который будет работать с обычным Statement :

UserLogin user = new UserLogin(); user.login(); try (Connection connect = MyConnection.getConnection()) < Statement statement = connect.createStatement(); String query = "SELECT userName, id, pass FROM users WHERE userName='" + user.name + "' AND pass = '" + user.pass + "'"; System.out.println(query); ResultSet resultSet = statement.executeQuery(query); while (resultSet.next())< System.out.printf("User: name=%s pass=%s\n", resultSet.getInt("id"), resultSet.getString("userName"), resultSet.getString("pass")); >MyConnection.closeConnect(); > catch (SQLException e)

Теперь если мы запустим этот метод и введем в консоль данные без инъекции:

user name: admin pass: admin User: name=admin pass=admin 

При этом сам запрос выглядит так:

 SELECT userName, id, pass FROM users WHERE userName='admin' AND pass = 'admin' 

Если допустить ошибку в имени или пароле, то данные выведены не будет.

Теперь попробуем использовать инъекцию( ‘ or’1’=’1 ), т.е. введем такие данные:

user name: admin' or'1'='1 pass: blabla 

То мы все равно получаем результат, несмотря на то, что пароль неверный:

 User: name=admin pass=admin 

При этом сам запрос теперь выглядит так:

 SELECT userName, id, pass FROM users WHERE userName='admin' or'1'='1' AND pass = 'blabla' 

т.к. выражение or’1’=’1′ всегда равно true , то даже без указания пароля мы получим все данные.

Как от этого защитит PreparedStatement ?

Метод который будет получать данные из базы с помощью PreparedStatement :

UserLogin user = new UserLogin(); user.login(); try (Connection connect = MyConnection.getConnection()) < String query = "SELECT userName, id, pass FROM users WHERE userName=? AND pass=?"; PreparedStatement statement = connect.prepareStatement(query); statement.setString(1, user.name); statement.setString(2, user.pass); System.out.println(statement); ResultSet resultSet = statement.executeQuery(); while (resultSet.next())< System.out.printf("User: name=%s pass=%s\n", resultSet.getInt("id"), resultSet.getString("userName"), resultSet.getString("pass")); >MyConnection.closeConnect(); > catch (SQLException e)

Все тоже самое, только заменили обычный Statement на PreparedStatement. Надеюсь вы на слово поверите, что при правильных данных мы получим верный результат, если нет то вот лог в консоли:

user name: user pass: pass User: name=user pass=pass Запрос: SELECT userName, id, pass FROM users WHERE userName='user' AND pass='pass' 

А теперь попробуем использовать инъекцию:

user name: user' or'1'='1 pass: inject 

И ответа не получаем, потому что запрос выглядит так:

 SELECT userName, id, pass FROM users WHERE userName='user\' or\'1\'=\'1' AND pass='inject' 

Т.е. все кавычки были отражены слешем, инъекция не удалась.

Отличие Statement от PreparedStatement :

Statement — вы должны заботиться о кавычках в запросе и ставить их там где они нужны.

PreparedStatement — вставляет значения в запрос и за счет методов setString setInt и прочих. Он сам понимает где нужны кавычки, а где нет. Соответственно все входные данных оборачивает ими.

Что такое SQL-инъекция на пальцах

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

SQL-инъекция — это довольно популярный вид уязвимости, существующей на стороне сервера. Она возможна в случае, когда сервер для хранения информации использует базу данных на основе SQL: MySQL, PostgreSQL, MSSQL и т. д.

Суть уязвимости в следующем. Сервер может подставлять данные, которые пришли от пользователя, прямо в SQL запрос. Например (код на PHP):

$id = $REQUEST[‘id’];

$q = “select * from Users where > Database::query($q);

Здесь id берется из запроса, который прислал клиент — веб-страница или мобильное приложение. Этот id становится частью SQL-запроса.

Ожидается, что от пользователя придет число в качестве id. Но технически пользователь может отправить любые данные. И злоумышленники этим пользуются.

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

Допустим, от пользователя придет id равный следующему значению:

5; drop table Users

Если подставить такой id без обработки в запрос выше, получится два запроса:

select * from Users where drop table Users

В итоге злоумышленнику удастся удалить таблицу Users. Подобным способом сформированный запрос и является SQL-инъекцией.

Существует множество способов защитить базу данных от инъекций. Этим обычно занимаются разработчики. А задача тестировщика — проверить возможные места для атаки.

Профилактика SQL-инъекций

SQL-инъекции (также известные как «Нарушение в целостности структуры SQL-запроса») являются одними из самых распространённых и наиболее опасных уязвимостей в вопросе безопасности. SQL-инъекции очень опасны, потому что они открывают двери хакерам в вашу систему через веб-интерфейс, и позволяют получить неограниченный доступ: например удалять таблицы, изменять базу данных, и даже получить доступ к внутренней корпоративной сети. SQL-инъекции это чисто программная ошибка, и не имеет ничего общего с хост-провайдером. Итак, вы занимались поисками безопасного JSP хостинга, PHP хостинга, или любого другого, вы должны знать, что за профилактику SQL-инъекций несут ответственность только разработчики, а не хост провайдер.

Почему же происходят SQL-инъекции

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

Риск SQL-инъекций возникает всякий раз, когда программист создает динамический запрос к базе, содержащий введённые пользователем данные. Это значит способов предотвращения SQL-инъекций два:

• Не использовать динамических запросов к базе.
• Не использовать пользовательских данных в запросах.

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

Что можно сделать для предотвращения SQL-инъекций

Хотя решение во многом зависит от конкретного языка программирования, все же общие принципы предотвращения SQL-инъекций схожи. Вот несколько примеров как это можно сделать:

• Использовать динамические запросы только в случае крайней необходимости.

Динамический запрос почти всегда можно заменить подготовленными выражениями (prepared statements), параметризованными запросами, или хранимыми процедурами. Например, вместо динамического SQL, в Java вы можете использовать PreparedStatement() с привязанными параметрами, в .NET вы можете использовать параметризованные запросы, такие как SqlCommand() или OleDbCommand()с привязанными параметрами, а в PHP вы можете использовать PDO со строгой типизацией параметризованных запросов (используя bindParam()).

В дополнение подготовленным выражениям (prepared statements), вы можете использовать хранимые процедуры. В отличие от подготовленных выражений (prepared statements), хранимые процедуры хранятся в базе, но в обоих случаях вначале определяется SQL-запрос, и в него передаются параметры.

• Проверка введенных данных в запросах.

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

• Не надеяться на волшебные Кавычки (Magic Quotes).

Включение параметра magic_quotes_gpc может предотвратить некоторые (но не все) SQL-инъекции. Magic quotes никак не последняя защита, и что еще хуже, иногда они выключены и вы не знаете об этом, или не имеете возможности его включить. Именно поэтому необходимо использовать код, который будет экранировать кавычки. Здесь кусок кода, предложенный Джоном Ли:
$username = $_POST[‘username’];
$password = $_POST[‘password’];
if (!get_magic_quotes_gpc()) $username = addslashes($username);
$password = addslashes($password);
>

• Регулярная и своевременная установка исправлений.

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

• Удаляйте весь функционал, который вы не используете.

Сервер баз данных это сложное создание и имеет намного больше функционала, чем вам требуется. А то, что касается безопасности, тут принцип «чем больше – тем лучше» не работает. Например, расширенная системная процедура xp_cmdshell в MS SQL дает доступ к операционной системе, а это просто мечта для хакера. Именно поэтому эту функцию нужно отключать, как и любые другие, позволяющие легко злоупотреблять функционалом.

• Использование автоматизированных средств нахождения SQL-инъекций.

Даже если разработчики следовали всем вышеописанным правилам, чтобы избежать динамических запросов с подстановкой непроверенных пользовательских данных, вы все равно должны подтвердить это тестами и проверками. Существуют автоматизированные средства тестирования, для выявления SQL-инъекций, и нет оправдания тем, кто не пользуется этими средствами для проверки процедур и запросов.
Один из простых инструментов (и один из более-менее надежных) для выявления SQL-инъекций это расширение для Firefox`а именуемое SQL Inject ME. После установки этого расширения, инструмент доступен по правому клику в контекстном меню, или из меню Tools → Options. Рабочая область SQL Inject ME показана на следующем скриншоте, и вы можете видеть как много видов тестов вы можете провести:

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

Множество параметров которые вы можете устанавливать для расширения SQL Inject ME, которые показаны на следующих двух скриншотах:

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

  • информационная безопасность
  • хакеры
  • уязвимости
  • инъекции

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 инъекции.

image

Пример ошибки, возникающей при проверке уязвимости

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

Практика. Варианты взлома сайта с уязвимостью на SQL внедрения

Итак, у нас есть уже упоминавшийся сайт test.ru. В базе хранится 4 новости, 3 из которых выводятся. Разрешение на публикацию новости зависит от парметра public (если параметр содержит значение 1, то новость публикуется).

image

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

image

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

Но так как мы уже проверяли сайт на уязвимость и он выдавал ошибку БД, то пробуем перебирать возможные варианты запросов.
В адресной строке плюс (+) выполняет роль пробела, так что не пугайтесь

image

В итоге удача улыбнулась и два запроса (первый и третий) вернули нам детальное описание четвёртой новости

Разбор примера изнутри

За получение детального описания новости отвечает блок кода:
$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);

Статья была подготовлена на основе практических навыков по защите веб-систем. Теория дело хорошее, но практика важнее и главное она работает.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *