SQL-инъекции. Что это?

Современный web-сервисы все чаще используют реляционные базы данных для хранения информации. С каждым днем эти базы пополняются различного рода информацией: от простейших общедоступных комментариев до различного рода секретной информации, в связи с этим жестко встает вопрос о защите информации от посторонних глаз. Одним из самых распространнех способов взлома баз данных являются SQL-инъекции (SQL-injection).
В этой статье Я расскажу немного о SQL-инъекциях и о основных способах защиты от подобного рода взломов.
Принцип атаки
Предположим, что сервер получает параметр id от пользователя и использует его для создания SQL-запроса:
$id = $_REQUEST['id']; $res = mysql_query("SELECT * FROM news WHERE id_news = $id");
К примеру, если на сервер передан id=1, то запрос будет:
SELECT * FROM news WHERE id = 1
“Выбрать всё из таблицы news где id=1″, то есть будет выбрана новость с id=1. И вот тут начинается самое интересное…
Если вместо числа в параметр id передать строку вида “-1 OR 1=1″, то наш запрос будет выглядить так:
SELECT * FROM news WHERE id = -1 OR 1=1
Наш запрос стал таким: “выбрать всё из таблицы news где id=-1 или 1=1″, поскольку единица всегда равна единице (1=1), то будет выбрана не одна новость с определенным id, а вся таблица news.
Таким образом SQL-инъекции основываются на передачи в качестве параметров конструкции SQL, тем самым нарушаю стандартную логику запроса.
Обработка входных параметров
При работе с информацией полученной от пользователя, стоит всегда думать о том, что каждый пользователь – это потенциальный злоумышленник, который хочет как-то навредить или получить доступ к Вашей приватной информации. Поэтому необходимо постоянно проверять на соответствие и обрабатывать полученные от пользователя данные, прежде чем передать их в SQL-запросе.
Некоторые правила
Всегда проверяйте соответствует ли полученная от пользователя информация той, которую Вы хотели получить от него.
1) Проверяйте, тот ли тип данных передается, который нужен в запросе. Допустим пользователь вводит в форму свой возраст в целочисленном формате. В этом случае необходимо проверить действительно ли пользователь передал число, а не строку?
<?php if(is_numeric($_GET['vozrast'])){ // Пользователь не злоумышленник :) } else{ echo('Ошибка ввода! Данные вводяться исключительно цифрами!') } ?>
2) Ограничивайте длину принимаемых данных, там где это возможно. Возвращаясь к примеру с возрастом, можно обойтись длинной в три символа (не всякий до 100 лет доживает, но случаи бывали).
<?php ... // Урезаем длину переменной $age до 3-х символов $age=substr($_REQUEST['age'], 0, 3) ... ?>
3) Экранируйте все спецсимволы в строковых параметрах.
<?php ... $query = "SELECT * FROM users WHERE user='".mysql_real_escape_string($user)."';"; ... ?>
Напоследок
О безопасности стоит задумываться в самом начале разработки, на этапе проектирования. Не стоит откладывать вопрос безопасности “на потом”, так как такой подход вместе с изменениями может внести кучу ошибок и даже поставить о вопрос о разработке нового “безопасного” проекта. При нахождении малейшей уязвимости, пусть даже её вероятность чрезвычайно мала, не стоит думать “обойдется”, лучше потратить время на устранение уязвимости, чем потом жалеть о утечке/потере данных.