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() не предназначена для защиты от инъекций, и не должна использоваться для этой цели

Собственно, основная причина, почему эту функцию не рекомендуют использовать - это как раз дурацкая идея про защиту от инъекций. Если человек понимает настоящее назначение этой функции, знает, где она неприменима, и что делать в таких случаях - то она вполне может использоваться. Беда только, что таких людей меньше процента.

В отличие от неё, подготовленные выражения защищают от инъекций (хотя они тоже, положа руку на сердце, предназначены не для этого) любые поддерживаемые ими типы данных. Почему и рекомендованы к применению.

→ Ссылка