Как я могу предотвратить инъекцию sql с php и mysql - PullRequest
1 голос
/ 15 июня 2010

У меня есть форма, в которую посетитель может вводить данные, и я хочу сохранить эти данные в базе данных mysql через переменную $ _POST.Что мне нужно, чтобы предотвратить инъекцию sql?

Ответы [ 4 ]

6 голосов
/ 15 июня 2010
3 голосов
/ 15 июня 2010

Я выступил с докладом на конференции PHP TEK-X в мае 2010 года на эту тему и попытался описать несколько способов защиты от SQL-инъекций. Не существует единственного метода, который был бы наилучшим во всех случаях, поэтому вы должны изучить несколько методов и использовать их все:

  • Проверяйте пользовательский ввод или любой другой контент из внешних источников (даже данные из вашей собственной базы данных) перед интерполяцией его в запрос SQL. Вы можете использовать расширение фильтра или регулярные выражения PHP, например.

  • Принудительный вывод внешнего содержимого в правильном формате. Например, (int) $_POST["userid"] указывает, что содержимое является простым целым числом, поэтому его можно безопасно использовать.

  • При включении динамического содержимого вместо литеральных значений в выражения SQL используйте подготовленные запросы с параметрами. Обратите внимание, что простое расширение mysql в PHP не поддерживает параметры запроса - используйте PDO . Я не использую mysqli, потому что его API несовместим и сложен в использовании.

  • При использовании предиката IN() нельзя использовать один параметр для списка значений. Объедините заполнители с несколькими параметрами, так как у вас есть значения в вашем списке. Это не сложно, это займет всего одну или две строки кода:

    $sql = "SELECT ... FROM ... WHERE user_id IN ("
        . join(",", array_fill(0,count($userid_list),"?")) . ")";
    $pdoStmt = $pdo->prepare($sql);
    $pdoStmt->execute($userid_list);
    
  • При использовании динамических имен таблиц, имен столбцов или ключевых слов SQL нельзя использовать параметры запроса. Вы должны интерполировать динамический контент. Но вы можете использовать методы белых списков, чтобы сопоставить ненадежный контент с легальными, безопасными идентификаторами и ключевыми словами.

См. Мою презентацию Мифы и ошибки SQL-инъекций для получения дополнительной информации и примеров.

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

0 голосов
/ 15 июня 2010

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

Чтобы отправить запрос в базу данных, у вас есть 2 варианта:

  1. Создайте запрос обычным способом, чтобы он выглядел точно так же, как SQL-запрос, который вы можете запустить в консоли sql.
    Чтобы сделать это, нужно понимать целый набор правил , а не просто «использовать mysql_real_escape_string».
    Правила, такие как:

    • строки должны быть заключены в кавычки и экранированы. это единственный смысл побега: это просто разделители easacpe! (и некоторые другие символы - символ завершения строки и сам символ выхода). Без окружающих кавычек mysql_real_escape_string просто бесполезен.
    • числа должны быть приведены к его типу явно. Хотя числам данных можно угрожать, как и строкам, есть некоторые числа, такие как параметры предложения LIMIT, которые нельзя экранировать и могут быть только приведены.
  2. Для отправки запроса и данных отдельно .
    Это наиболее предпочтительный способ, поскольку он может быть сокращен до «использования привязки». Все строки, числа и параметры LIMIT могут быть связаны - не беспокойтесь вообще.
    Используя этот метод, ваш запрос с заполнителями отправляется в базу данных как есть, а связанные данные отправляются в отдельных пакетах, поэтому он не может вмешиваться. Это как разделение кода и данных . Вы отправляете свою программу (сам запрос) отдельно от данных.

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

$orders  = array("name","price","qty");
$key     = array_search($_GET['sort'],$orders));
$orderby = $orders[$key];
$query   = "SELECT * FROM `table` ORDER BY $orderby";

или динамический поиск:

$w     = array();
$where = '';

if (!empty($_GET['rooms']))     $w[]="rooms='".mesc($_GET['rooms'])."'";
if (!empty($_GET['space']))     $w[]="space='".mesc($_GET['space'])."'";
if (!empty($_GET['max_price'])) $w[]="price < '".mesc($_GET['max_price'])."'";

if (count($w)) $where="WHERE ".implode(' AND ',$w);
$query="select * from table $where";

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

и т. Д.

0 голосов
/ 15 июня 2010

Прочтите это, и в следующий раз сделайте поиск:

https://stackoverflow.com/questions/1973/what-is-the-best-way-to-avoid-sql-injection-attacks

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...