Способы защиты от SQL-инъекций

Самый простой способ защиты от SQL-инъекции – «обрамлять» параметры SQL-запроса одиночными кавычками ('), поскольку через GET- и POST-запрос невозможно передать символ одиночной кавычки (он будет автоматически заменен сочетанием символов – \' – т.е. экранироваться).
SELECT * FROM `table_name` WHERE `param` = '$param_name' ORDER BY `sort` ASC;
SQL-запрос в случае инъекции будет выглядеть примерно так:
SELECT * FROM `table_name` WHERE `param` = '10 union select 1,2,3 /*' ORDER BY `sort` ASC;
Т.е. для обработчика запросов, при отбрасывании части запроса после /*, запрос будет выглядеть примерно так:
SELECT * FROM `table_name` WHERE `param` = '10 union select 1,2,3
Обработчик запросов, не найдя закрывающей кавычки посчитает этот запрос ошибочным и не выполнит его. Если попытаться GET-запросом передать фрагмент кода с кавычкой:
10' union select 1,2,3/*
, то, после отбрасывания комментария, SQL-запрос будет выглядеть так:
SELECT * FROM `table_name` WHERE `param` = '10\' union select 1,2,3
В этом случае обработчик также не выполнит этот запрос, потому что не найдет закрывающей кавычки, т.к. сочетание символов \' будет расценено не как закрывающая кавычка, а как внутренний символ ', который должен содержаться в поле `param`.
Однако такой способ не гарантирует стопроцентной защиты от SQL-инъекций. Приведем несколько дополнительных способов
Всегда проверяйте числовые параметры функцией intval. При проверке такого параметра:
10' union select 1,2,3/*
, функция intval вернет значение 10, что исключает возможность SQL-инъекции. Однако не все параметры являются числовыми. Например:
http://somesite.dom/index.php?section=about
Здесь параметр section является строковым, и функция intval здесь не может быть применена. Что бы избежать вредоносного запроса, можно воспользоваться следующими функциями:
mysql_escape_string – экранирует все спецсимволы;
Так же можно проверять строковые параметры на наличие в них таких слов как "select", "union", "order", "char", "where", "from".
Пример функции на PHP 5:
function escape_inj ($text) {
  $text = strtolower($text); // Приравниваем текст параметра к нижнему регистру
  if (
    !strpos($text, "select") && // 
    !strpos($text, "union") && //
    !strpos($text, "select") && //
    !strpos($text, "order") && // Ищем вхождение слов в параметре
    !strpos($text, "where") && // 
    !strpos($text, "char") && //
    !strpos($text, "from") //
  ) {
    return true; // Вхождений нету - возвращаем true
  } else {
    return false; // Вхождения есть - возвращаем false
  }
}
$section = $_GET[section]; // Читаем параметр
if (!escape_inj ($section)) { // Проверяем параметр
  echo "Это SQL-инъекция.";
  exit ();
} else {
  $result = mysql_query ("SELECT * FROM `tbl_name` WHERE `section` = $section ");
  ... // Продолжаем работу
}
Никогда не храните пароли в базе данных в открытом виде, обязательно шифруйте их (например, функцией sha1). С помощью SQL-инъекции легко "достать" данные из базы данных, а если они будут зашифрованы, то есть большая вероятность того, что злоумышленник не сможет ими воспользоваться.
Для обеспечения конфиденциальности логина и пароля для доступа к базе данных, функции подключения к базе данных лучше хранить в отдельном файле и подключать его в каждой странице сайта.
Так же, отключение вывода на экран ошибок, возникших при неверном запросе, сильно усложняет задачу злоумышленнику. Что бы отключить вывод ошибок достаточно написать следующее (например, в файле подключения базы данных):
ini_set('display_errors', '0');
Старайтесь проверять результат каждого выполняемого запроса на выполнение и количество найденных записей. Если их количество равно нулю, перенаправляйте пользователя, например, на главную страницу, это обеспечит хорошую защиту от SQL-инъекций.
Пример на PHP 5:
$section = $_GET[section]; // Читаем параметр
$result = mysql_query ("SELECT * FROM `tbl_name` WHERE `section` = $section "); // выполняем запрос
if (!$result || mysql_num_rows ($result) == 0) { // Кол-во найденных полей = 0, или запрос не был выполнен
  header ("Location: http://$_SERVER[HTTP_HOST]/"); // Уходим на главную страницу
  exit ();
} else {
  ... // Продолжаем работу
}
Если Ваш сайт не содержит разделов, в которых производится запись или редактирование строк в базе данных, то необходимо у пользователя базы данных, под которым происходит соединение с базой, отключить все права, кроме права на чтение данных. По-умолчанию, у пользователя базы данных есть права и на удаление, и на редактирование. Для разделов сайта, требующих больших прав, например книга отзывов или форум стоит завести отдельного пользователя, у которого будет право на редактирование только конкретной таблицы. А для системы управления сайтом необходимо завести отдельного пользователя базы данных, т.к. ему необходимы полные права.
Все описанные выше способы не гарантируют стопроцентной защиты от SQL-инъекций, однако, помогут предотвратить их в подавляющем большинстве случаев. krut

URL: https://visavi.net/articles/196