SQL инъекция в числовой параметр в PHP
Давайте теперь рассмотрим SQL инъекцию,
осуществляемую в числовой параметр.
В этом случае наша длинная фунцкия mysqli_real_escape_string
не поможет, так как хакерском коде просто
не будет кавычки - функции нечего экранировать.
Давайте посмотрим на практике. Пусть у нас есть следующая ссылка, с помощью которой осуществляется GET-запрос:
<a href="?id=2">ссылка</a>
Пусть мы получаем содержимое GET-параметра в переменную:
<?php
$id = $_GET['id'];
?>
Пусть мы хотим достать из базы
продукт с этим id
:
<?php
$query = "SELECT name, cost FROM prods WHERE id=$id";
$res = mysqli_query($link, $query);
$row = mysqli_fetch_assoc($res);
?>
Обратите внимание на то, что, так как в переменной у нас числовое значение, то внутри запроса мы эту переменную не берем в одинарные кавычки. В этом и проявляется разница между строковыми и числовыми параметрами.
Наш GET-запрос содержится в адресе ссылки. Злоумышленник может как отредактировать ссылку в отладчике браузера, так и поменять значение GET-параметра в адресной строке браузера.
Давайте посмотрим, как злоумышленник сможет использовать эту уязвимость.
Вариант 1
Выполним безобидную атаку, просто чтобы проверить, что мы можем модифицировать SQL запрос. Изменим значение GET-параметра на следующее:
?id=-1 or cost=1000
В этом случае выполнится следующий запрос, который достанет продукт с заданной хакером ценой:
SELECT name, cost FROM prods WHERE id=-1 or cost=1000
Вариант 2
А теперь рассмотрим совсем не безобидную
атаку. Злоумышленник может выполнить
UNION
запрос и получить данные из любой таблицы!
Вот так:
?id=-1 UNION SELECT login, password FROM users WHERE role=1
В результате выполнится следующий запрос,
который достанет логин и пароль
администратора (напомню, у него role
в значении 1
):
SELECT name, cost FROM prods WHERE id=-1
UNION SELECT login, password FROM users WHERE role=1
Если пароли на сайте хранятся не в хешированном виде или для хеширования используется устаревший md5, то все - сайт взломан.
При атаке через UNION
запрос хакеру
важно, чтобы количество полей в исходной
выборке и в подключаемой совпадало.
Но не переживайте, хакер легко подберет
нужное количество, пусть и не сразу!
Защита
Как уже упоминалось ранее, защита
через mysqli_real_escape_string
не работает в случае числовых параметров:
<?php
$id = mysqli_real_escape_string($link, $_GET['id']); // не работает
?>
В данной ситуации защита заключается в принудительном приведении значения параметра к числу:
<?php
$id = (int) $_GET['id'];
?>
Практические задачи
Опробуйте все описанные варианты использования уязвимости. Устраните уязвимость. Убедитесь, что она исчезла.
Устраните уязвимость в следующем коде:
<?php
$from = $_GET['from'];
$query = "SELECT * FROM products LIMIT $from";
$res = mysqli_query($link, $query);
for ($data = []; $row = mysqli_fetch_assoc($res); $data[] = $row);
var_dump($data);
?>