SQL-инъекция, обходящая mysqli_real_escape_string
Распространено мнение, что функция, призванная защищать от SQL-инъекций mysqli_real_escape_string на самом деле не способна защитить.
Ситуация: Таблица users содержит информацию о пользователе: поля login, password и другие. Форма на сайте принимает в два поля логин/пароль и посылает в следующий скрипт на PHP:
<?php
//$_REQUEST=['login'=>'user', 'password'=>'123456'];
//$db - соединение MySQLi
['login'=>$login,'password'=>$password]=$_REQUEST;
print_r([$login,$password]);
$login=$db->real_escape_string($login);
$password=$db->real_escape_string($password);
print_r([$login,$password]);
$q="SELECT * FROM users WHERE login='$login' AND password='$password'";
print_r($q);
$res=$db->query($q);
if(!$res){
if($db->error)
echo "SQL ERROR {$db->errno}:{$db->error}\n$q";
exit;
}
$row=$res->fetch_assoc();
print_r($row);
exit;
Пожалуйста, приведите пример таких полей массива $_REQUEST, которые позволят получить из БД неразрешённые данные, то есть те, которые не соответствуют введённым логину/паролю. Я не понимаю. Я не смог получить.
Ответы (1 шт):
Распространено мнение, что функция, призванная защищать от SQL-инъекций
Это весьма распространённая, но совершенно некорректная формулировка.
Нигде в официальной документации не написано, что эта функция "призвана защищать от инъекций".
приведите пример таких полей массива $_REQUEST
Такой пример привести нельзя. В данном упрощенном изолированном примере запрос безопасен. Но при этом
SQL-инъекция, обходящая mysqli_real_escape_string
выглядит совершенно элементарно
$id = $db->mysqli_real_escape_string($_GET['id']);
$sql = "SELECT * FROM users WHERE id=$i";
если в $_GET['id'] будет например sleep(10000); то мы получим стопроцентную инъекцию, из палаты мер и весов.
Этот дурацкий пример как раз наглядно и демонстрирует, что ни для какой "защиты" эта функция не предназначена. Если бы была, то защищала бы. А поскольку эта функция всего лишь "экранирует специальные символы в строке для использования в SQL-выражении", то во-первых, защита от инъекций, по сути является для неё всего лишь побочным эффектом. А исходным предназначением (тем, что она "призвана делать") является обеспечение корректности синтаксиса запроса. То есть, эта функция должна применяться при помещении динамических строк в запрос, независимо каких бы то ни было инъекций. А во-вторых, очевидно, что даже в виде побочного эффекта, её область применения ограничена только строками. Любые другие элементы запроса она не защищает никак.
Отсюда мы можем вывести правильную формулировку:
Фуцнкция mysqli_real_escape_string() не предназначена для защиты от инъекций, и не должна использоваться для этой цели
Собственно, основная причина, почему эту функцию не рекомендуют использовать - это как раз дурацкая идея про защиту от инъекций. Если человек понимает настоящее назначение этой функции, знает, где она неприменима, и что делать в таких случаях - то она вполне может использоваться. Беда только, что таких людей меньше процента.
В отличие от неё, подготовленные выражения защищают от инъекций (хотя они тоже, положа руку на сердце, предназначены не для этого) любые поддерживаемые ими типы данных. Почему и рекомендованы к применению.