HTML, Excel, Word, SEOВеб-программинг ⇒ sql-injection

Практические примеры

Примеры веб-программирования
· Интернет-платежи
· Авторизация клиентской оплаты
· Защита от уязвимости sql-injection
· Как пользоваться Google Analytics
· Электронная коммерция в Google Analytics
· Использование Google Analitycs для split тестирования
Сайт от А до Я
· С чего начать
· ПО для сайта
· Домен и хостинг
· Структура сайта
· Главная страница
· Фон страницы
· Анализ главной стр
· Регистрация сайта
· Веб-графика

 
Сабмит сайта в каталоги

Практические советы по предотвращению уязвимостей вида sql-injection


Автор: Иван Коржавин
email: korjavin@yandex.ru

Общая идея.

В процессе работы нашего веб приложения мы работаем с данными, которые получаем от наших пользователей. Это могут быть html формы, http get/post запросы, ajax запросы, и прочее.
При недостаточной проверке внешних данных, злоумышленник может подобрать такой набор, который заставит наш код выполнить не планируемое действие. Атак такого типа много, это и переполнение стека, и перегрузка системы ведущая к отказам в обслуживании, и другие. Мы рассмотрим узкий класс таких атак sql injection или "внедрение sql" как самый распространенный.


Простейший пример

В самом простейшем виде, атака выглядит так:


Пример посложнее

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


Используемый запрос:


Вместо перебора логин пароль, злоумышленник передаст вместо login строчку

Admin' --  

Получив запрос:

 select * from admins where login='Admin' -- ' and pass='' 

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


Пример посложнее с кодировкой

Форма аналогичная предыдущей, но каким либо образом в форму запрещено вводить пробелы и кавычки.

Злоумышленник передает строку:

Admin%27/*test*/--+

В этой строке, %27 способ передать кавычку, и два способа передать пробел. Первый с помощью комментария, а для СУБД mysql любой комментарий разделитель. Второй с помощью символа +


Рубежи обороны

Разберем основные рубежи, где мы можем фильтровать эти атаки:


  1. Проверка данных на стороне браузера клиента с помощью javascript.
  2. Проверка введенных пользователем данных на стороне сервера - web сервера.
  3. Проверки введенных пользователем данных на стороне скрипта - интерпретатора php.
  4. Изменение способа формирования строки запроса

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


Второй пункт - web сервер, скорее всего, первым принимает данные пользователя, и уже здесь мы можем произвести некоторые, простейшие фильтрации: обрезать query string по стоп-словам.

По моему мнению, это очень слабый способ. Мы никогда не сможем предусмотреть все варианты передаваемых данных, и более того многие из них, будут абсолютно легальны и не связаны с атаками в определенных контекстах.
К тому же данные могут передаваться закодировано-искаженным способом и различными методами post/put.


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

%27+having+1%3D1--+

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

Третий пункт - скрипт php. В коде php мы смело вставляем полученные от пользователя данные в запрос, что категорически нельзя делать. Мы обязаны проверить переданные нам параметры с помощью регулярных выражений, или пропустить их через функции удаляющие экранирование, и прочее, например mysql_real_escape_string.


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


Четвертый способ - изменение способа формирования запроса. Например:

В этом примере мы используем некий шаблон для sql, который заполняем данными с помощью функции sprintf, а она проведет для нас проверку типов.


Но есть способ еще лучше. Использовать параметры sql. Пример:

В этом примере много плюсов по сравнению с предыдущими пунктами. Во первых, мы по прежнему проверяем тип параметра, функцией bind_param, во вторых мы строим запрос с помощью СУБД без пользовательских данных.


Это означает что запрос который мы передали с помощью функции prepare, будет разобран на стороне mysql заранее. Будет составлен его план, и запрос преобразован в структуры mysql. Поэтому, если пользовательские данные каким то образом попробуют "сломать" логику запроса, он не будет выполнен, и поэтому же пользовательские данные не будут рассматриваться как управляющие команды sql.


Дополнительным плюсом этого метода будет то, что если запрос нужно выполнить несколько раз с разными данными, вам не нужно будет конструировать и передавать его в СУБД, вы просто передадите следующий набор параметров, и сэкономите время на процедурах генерации запроса в вашем скрипте, и на разборе запроса со стороны СУБД.


Очень рекомендую использовать этот способ - sql запросы с параметрами.




В начало страницы



В начало страницы