Самый простой способ защиты от 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 {
... // Продолжаем работу
}
?>
Строк: 1
Если Ваш сайт не содержит разделов, в которых производится запись или редактирование строк в базе данных, то необходимо у пользователя базы данных, под которым происходит соединение с базой, отключить все права, кроме права на чтение данных. По-умолчанию, у пользователя базы данных есть права и на удаление, и на редактирование. Для разделов сайта, требующих больших прав,например книга отзывов или форум стоит завести отдельного пользователя, у которого будет право на редактирование только конкретной таблицы. А для системы управления сайтом необходимо завести отдельного пользователя базы данных, т.к. ему необходимы полные права.
Все описанные выше способы не гарантируют стопроцентной защиты от SQL-инъекций, однако, помогут предотвратить их в подавляющем большинстве случаев.
call_user_method() (используйте call_user_func())
call_user_method_array() (используйте call_user_func_array())
define_syslog_variables()
dl()
ereg() (используйте preg_match())
ereg_replace() (используйте preg_replace())
eregi() (используйте preg_match() с модификатором \'i\')
eregi_replace() (используйте preg_replace() с модификатором \'i\')
set_magic_quotes_runtime() и ее синоним magic_quotes_runtime()
session_register() (используйте суперглобальный массив $_SESSION)
session_unregister() (используйте суперглобальный массив $_SESSION)
session_is_registered() (используйте суперглобальный массив $_SESSION)
set_socket_blocking() (используйте stream_set_blocking())
split() (используйте preg_split())
spliti() (используйте preg_split() с модификатором \'i\')
sql_regcase()
mysql_db_query() (используйте mysql_select_db() и mysql_query())
mysql_escape_string() (используйте mysql_real_escape_string())
Передача строки, задающей категорию функций, на которые будет влиять установка локали, сейчас считается устаревшим вариантом. Используйте вместо этого семейство констант LC_*
Параметр is_dst в функции mktime(). Вместо него используйте новые функции работы с временными зонами.
Не вижу тут что бы mysql_real_escape_string() устарела.
вместо mysql_escape_string используйте mysql_real_escape_string.
1. mysql_escape_string устарело и будет в будущем удалено.
2. mysql_real_escape_string учитывает кодировку.