MySQL и SQL-инъекция

Если вы вводите пользовательский ввод через веб-страницу и вставляете его в базу данных MySQL, есть вероятность, что вы оставили себя открытым из-за проблемы безопасности, известной как SQL Injection. В этой главе вы узнаете, как предотвратить это и защитить свои сценарии и операторы MySQL.

SQL-инъекция обычно происходит, когда вы запрашиваете у пользователя ввод, например его имя, и вместо имени он дает вам инструкцию MySQL, которую вы бессознательно запускаете в своей базе данных.

Никогда не доверяйте данным, предоставленным пользователем, обрабатывайте эти данные только после проверки; как правило, это делается путем сопоставления с образцом. В следующем примере имя пользователя ограничено буквенно-цифровыми символами плюс подчеркивание и имеет длину от 8 до 20 символов - при необходимости измените эти правила.

if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
   $result = mysql_query("SELECT * FROM users WHERE username = $matches[0]");
} else  {
   echo "username not accepted";
}

Чтобы продемонстрировать эту проблему, рассмотрим следующий отрывок.

// supposed input
$name = "Qadir'; DELETE FROM users;";
mysql_query("SELECT * FROM users WHERE name = '{$name}'");

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

К счастью, если вы используете MySQL, mysql_query()Функция не позволяет складывать запросы или выполнять несколько запросов за один вызов функции. Если вы попытаетесь сложить запросы, вызов не удастся.

Однако другие расширения базы данных PHP, такие как SQLite и PostgreSQL, успешно выполняет составные запросы, выполняя все запросы, представленные в одной строке, и создает серьезную проблему безопасности.

Предотвращение внедрения SQL

Вы можете грамотно обрабатывать все escape-символы в таких языках сценариев, как PERL и PHP. Расширение MySQL для PHP предоставляет функциюmysql_real_escape_string() для экранирования входных символов, специальных для MySQL.

if (get_magic_quotes_gpc()) {
   $name = stripslashes($name);
}

$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM users WHERE name = '{$name}'");

LIKE затруднительное положение

Чтобы решить проблему LIKE, пользовательский механизм экранирования должен преобразовывать предоставленные пользователем символы% и _ в литералы. Использоватьaddcslashes(), функция, которая позволяет указать диапазон символов, который нужно экранировать.

$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");