Защита от SQL инъекций средствами PHP и PDO

Абстрактный доступ к базам данных, такой как php Portable Data Objects (PDO) вовсе не какая-либо новая концепция в программировании, но многие из разработчиков до сих пор не осознают в полной мере какие преимущества в области защиты кода предоставляет использование данной технологии, в данной статье речь пойдет о SQL инъекциях.
SQL инъекция – это код или запрос к БД, направленный на переполнение буфера web-приложения. Каждый разработчик скриптов должен заботиться о том, чтобы разрабатываемый им код был  защищен от подобных уязвимостей. Для тех кто не в курсе, SQL инъекция –  это техника применяемая хакерами, использования «дыр» программного кода для выполнения произвольных SQL запросов, приводящих к уничтожению, повреждению или непредусмотренной модификации данных. В данной статье мы не будем глубоко вникать в философию SQL инъекций, но небольшой пример, думаю, привести стоит:
Главная страница вашего сайта содержит форму входа пользователей, связанную с php скриптом, который определяет статус пользователя (зарегистрированный или нет) и наделяет его определенными полномочиями или делает доступным определенный дополнительный набор сервисов сайта. Форма входа передает сценарию две переменные методом POST:

username=fred&password=Fr3dRul3z

Пученные данные используются при построении SQL запроса к БД, для идентификации пользователя:

$sql = "SELECT * FROM users WHERE username = '".$_REQUEST['username']."' AND password = '".$_REQUEST['password']."'";

Данный код сформирует запрос:

SELECT * FROM users WHERE username = 'fred' AND password = 'Fr3dRul3z'

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

' OR 1==1 --  

А поле пароля нужно оставить пустым. В итоге  SQL запрос к базе данных примет вид:

SELECT * FROM users WHERE username = 'fred' OR 1==1 -- ' AND password = ''
В результате такого запроса в БД будут выбраны все пользователи, так как выражение 1==1 всегда истинно. Вторя часть запроса блокируется оператором комментария ‘--‘.  Чтобы избежать атаки подобного рода, необходимо проверять данный полученный из формы и удалять все, что может быть использовано для модификации SQL запроса. В случае работы с MySQL вы можете воспользоваться функцией mysql_real_escape_string().
Основная цель слоев абстрагирования баз данных подобно PDO -  чистая абстракция кода не связанная с базой данных, таким образом, теоретически появляется возможность переключения между базами MySQL, PostgreSQL или Oracle с минимальными модификациями программы. На практике все зависит от того на сколько ваш код привязан к определенной платформе, например к триггерам или хранимым процедурам, но если вы не зависите от них вообще, т.е. просто работаете с обычными запросами типа INSERT/UPDATE/DELETE – у вас не должно возникнуть никаких сложностей. Еще одно полезное свойство – предопределенные выражения, большинство слоев абстракции баз данных (включая PDO) реализуют этот механизм как возможность выполнения одинаковых запросов много раз,  но с разными параметрами. Теперь, мы построим запрос по методологии PDO. За основу возьмем SQL запрос приведенный выше. Выражение разработаем с использованием меток-заполнителей:
$sql = "INSERT INTO fruits (name, price) VALUES (?, ?)";

и выполним запрос со следующими предустановленными параметрами, переданными в слой абстракции следующим образом:

$sth = $dbh->prepare($sql); 
$sth->execute(array($fruit, $price));

Когда данные обработаны в PDO, они напрямую передаются драйверу базы данных, либо запрос строиться безопасным образом внутри данного расширения. Как можно заметить, это простой путь решения проблемы с SQL инъекциями.
Однако  при использовании предопределенных выражений совместно с PDO необходимо знать некоторые нюансы, чтобы избежать неприятных ситуаций. Например, в MySQL клиенте некоторые запросы, составленные посредством предопределенных выражений, не могут быть выполнены[1], а так же они не используют  кэш [1][2], что может замедлить работу вашего web-приложения.
Гарантированная безопасность при использовании предопределенных выражений звучит успокаивающе, но разработчики не должны принимать PDO и другие слои абстракции\предопределенные выражения за абсолютную защиту от взлома. Любые входящие данные должны проверяться, PDO –  дополнительная линия обороны. Это расширение не закрывает все множество уязвимостей, посредством которых может быть нанесен вред вашей информации, но в то же время, PDO неплохо справляется с вопросом предотвращения SQL инъекций.
PDO является частью php начиная с версии 5.1.0, вышедшей в ноябре 2005.

[1] http://dev.mysql.com/doc/refman/5.0/en/c-api-prepared-statement-problems.html
[2] http://dev.mysql.com/doc/refman/5.0/en/query-cache-how.html


 

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


Защитный код
Обновить

Разработчику

Скрипты