Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Разница между Statement и PreparedStatement


Автор: Alagert 22.8.2006, 17:21
Доброго времени суток!

Народ помогите советом!
Есть прослойка между приложением и MSSQL Server. Она умеет генерить запросы из инфы, пришедшей от приложения и выполнять их на сервере. Сейчас это сделано след образом: из запроса от приложения собираются искомые поля и ограничения. На их основе формируется sql запрос в виде строки.(String) Затем Создается Statement и выполняется. Все работает отлично.

Но, наш заказчик тут выдал следущую мысль:
Цитата
remember use preventing techique for sql injection.

и вот такой пример:
Код

PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM BOOKLIST WHERE ISBN = ?");

...

ParameterMetaData pmd = pstmt.getParameterMetaData();

int colType = pmd.getParameterType(1);



Чем поверг нас в большие непонятки.
Так вот, собственно сам вопрос: чем PreparedStatement лучше с точки зрения какой либо безопасности? 
Или может мы упустили какой то другой момент?

Заранее спасибо!

Автор: Devorior 22.8.2006, 17:49
На мой взгляд, проверки на подставляемые в коде значения надо проводить по мере получения параметров извне (прослойка, браузер или другое приложение). А разница между Statement и PrepareStatement в плане безопасности отстуствует и не надо об этом зацикливаться. Тщательно проверяйте все что идет на входе до выполнения каких-либо операций.

Автор: Stampede 22.8.2006, 18:29
Цитата(Devorior @  22.8.2006,  08:49 Найти цитируемый пост)
А разница между Statement и PrepareStatement в плане безопасности отстуствует и не надо об этом зацикливаться


Весьма смелое, но, увы, ошибочное заявление. Чтобы понять, о чем говорит заказчик, надо представлять себе технику SQL injection аттак. Если на пальцах, то примерно следующим образом.

Допустим, на странице вебсайта есть поле для логина/пароля. Что делает злоумыленник? Очень тривиальную вещь! Он исходит из предположения, что параметры входа так или иначе будут использованы серверным скриптом в виде следующей конструкции:

Код

select ...
  where login_name = '<введенное имя>' and password = '<введенный пароль>'


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

логин: admin
пароль: asdf' or 1 = 1

Нетрудно видеть, что если скрипт не предусматривает защиту от SQL injection, то по исполнении сгенерированного запроса злоумышленнику с радостью предоставят все админские полномочия:

Код

select ...
  where login_name = 'admin' and password = 'asdf' or 1 = 1


Так вот, в случае использования PreparedStatement такая подстановка в принципе невозможна, что, собственно, и имел в виду заказчик.

Автор: Devorior 22.8.2006, 18:34
все верно, надо вырезать "левое" из логина и пароля, а потом подставлять в SQL, неважно как реализуемый

Автор: chief39 22.8.2006, 18:58
Уххх.... точно... вот это ребусик smile
В репу.

Автор: Stampede 22.8.2006, 19:17
Цитата(Devorior @  22.8.2006,  09:34 Найти цитируемый пост)
надо вырезать "левое" из логина и пароля, а потом подставлять в SQL


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

Поэтому еще раз: если запросы фиксированного формата, то использование PreparedStatement было бы самым простой и естественной формой защиты. Если, как у вас, запросы строятся "на лету", то тут трудно предложить что-либо конкретное, не владея подробной инфой о структуре проложения и характере запросов.

Например, что из себя представляет типичный запрос? Сколько и каких параметров он принимает? Сколько таблиц могут фигурировать в запросе? Откуда берутся метаданные?

Ну и так далее.

Автор: Alagert 22.8.2006, 23:50
Stampede, Огромнейшее спасибо! Есть над чем поразмыслить. Завтра с работы подкину новую партию мыслей для обсуждения.

Автор: Bulat 23.8.2006, 08:14
Stampede, вообще верно, но допустим если у меня еще будет проверка на вводимые числа? Если я в промежутке(допустим вместо пароля пин карточки, что есть цифры) я еще буду проверять чтобы все символы были цифрами, то как минимум наличие пробела и "=" уже не даст дойти до запроса.
А написать такую бональную проверку, две минуты.  smile 

Автор: serious 23.8.2006, 09:34
А насколько безопасен такой код:
Код

Session session = getSession();
Query query = session.createQuery("from User where email = :email");
query.setString("email", email);
User user = (User) query.uniqueResult();

если логин осуществляется только по e-mail.

Автор: Alagert 23.8.2006, 10:51
Всем спасибо за советы. Ща сидел проверял на подобные штуки наш код. 
Вроде бы мы не наткнулись на эти грабли. Тк все поля обрабатываются и засовываются в ковычки, то пример, приведенный Stampede, не работает. Ща еще капаю в эту сторону. Но пока склоняюсь к тому, что не буду ни чего переделовать smile

Автор: LSD 23.8.2006, 10:58
Цитата(Alagert @  23.8.2006,  11:51 Найти цитируемый пост)
Тк все поля обрабатываются и засовываются в ковычки, то пример, приведенный Stampede, не работает.

Интерестно как это у вас происходит, учитываюя что код Stampede работает с кавычками?

Автор: serious 23.8.2006, 11:08
http://www.unixwiz.net/techtips/sql-injection.html

Автор: Alagert 23.8.2006, 11:46
Цитата(LSD @  23.8.2006,  10:58 Найти цитируемый пост)
Интерестно как это у вас происходит, учитываюя что код Stampede работает с кавычками?

К примеру, у нас полдучается вот такой код:
Код

SELECT * FROM ecjournal WHERE  (CompanyId='egdf or 1=1')

Соответсвенно, OR внутри строкового параметра. Поэтому все норм. 
Я пока не могу говорить, что наш код полностью от этого защищен(Я скорей  уверен в том, что это не так smile)

Пока ищу еще возможности для атаки.

Автор: LSD 23.8.2006, 13:21
Цитата(Alagert @  23.8.2006,  12:46 Найти цитируемый пост)
Соответсвенно, OR внутри строкового параметра. Поэтому все норм.

Ты невнимательно прочитал пост Stampede, там именно такой случай и рассматривается.
Пусть мы генерируем запрос таким макаром:
Код
String query = "SELECT * FROM ecjournal WHERE  (CompanyId='" + param + "')";

Если в качестве param передать строку:
Код
String param = "1' or '1' = '1";

То получим запрос:
Код
SELECT * FROM ecjournal WHERE  (CompanyId='1' or '1' = '1')

Автор: Alagert 23.8.2006, 13:36
smile Ты идешь моим же путем! Я проверял этот вариант. Но он тоже не проходит, тк наша прога при получении ограничений, просматривает их. Если находит внутри ковычки, то она экранирует их ковычкой. Те этот пример у нас будет выглядеть так:
Код

SELECT * FROM ecjournal WHERE  (CompanyId='1'' or ''1''=''1')


Большое спасибо за кропотливость! 

Автор: LSD 23.8.2006, 13:42
А даты и числа с ними что делать?

Автор: Alagert 23.8.2006, 13:48
Цитата(LSD @  23.8.2006,  13:42 Найти цитируемый пост)
А даты и числа с ними что делать? 

А тут уже работает веб интерфейс, если в поле, принимающее дату, ввели какую нить непотребщину, он ругается. Точно так же обстоят дела и с числами.

Может подскажешь еще какой нить способ подловить систему? 

Автор: UnicornMirage 23.8.2006, 15:35
Цитата(Alagert @ 23.8.2006,  13:48)
Цитата(LSD @  23.8.2006,  13:42 Найти цитируемый пост)
А даты и числа с ними что делать? 

А тут уже работает веб интерфейс, если в поле, принимающее дату, ввели какую нить непотребщину, он ругается. Точно так же обстоят дела и с числами.

Может подскажешь еще какой нить способ подловить систему?

а если эти данные ввести как параметры GET-запроса минуя форму и тем самым алгоритмы проверки на корректность?

Автор: LSD 23.8.2006, 20:27
Цитата(UnicornMirage @  23.8.2006,  16:35 Найти цитируемый пост)
а если эти данные ввести как параметры GET-запроса минуя форму и тем самым алгоритмы проверки на корректность?

Мысль! Можно например сохранить HTML страничку и изменить тип поля.

Автор: Alagert 23.8.2006, 22:49
В этом случае у меня так сделано: если должна придти дата, то я на основе ее строкового представления создаю java.util.Date. Соответсвенно, если туда напихакать какую нить хрен, дата просто напросто не создаться. Ну и в sql запрос ничего не передасться. С числами примерно так же. 
Проверял - работает.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)