Что такое SQL-инъекция

Ответ

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

Пример уязвимого кода:

$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";

Если ввести ' OR '1'='1 в поле username, запрос превратится в:

SELECT * FROM users WHERE username='' OR '1'='1' AND password='...'

Это вернёт все записи из таблицы users.

Защита:

  1. Используйте подготовленные выражения (PDO/mysqli):
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=:username AND password=:password");
$stmt->execute(['username' => $username, 'password' => $password]);
  1. Валидация и экранирование ввода.
  2. Принцип минимальных привилегий для БД.

Ответ 18+ 🔞

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

Представь, у тебя есть форма входа. Пользователь вводит логин и пароль, а твой скрипт, как доверчивый лох, тупо лепит это всё в SQL-запрос. Вот так, блядь:

$username = $_POST['username'];
$password = $_POST['password'];
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";

Выглядит вроде норм, да? А теперь смотри сюда, какой-нибудь хитрожопый пидарас шерстяной может в поле username вписать не 'admin', а вот такую хуйню: ' OR '1'='1.

И что получается? Твой запрос, ёпта, превращается в полную пиздопроебибну:

SELECT * FROM users WHERE username='' OR '1'='1' AND password='...'

А '1'='1' — это всегда правда, ядрёна вошь! И этот запрос вернёт тебе вообще всех пользователей из таблицы. А если там первая запись — это админ, то злоумышленник заходит как админ, и доверия к твоему коду — ноль ебать. Сам от себя охуеешь, когда это обнаружат.

Как не быть распиздяем и защититься?

  1. Используй подготовленные выражения. Это святое, блядь. Всё равно, через PDO или mysqli. Смысл в том, что запрос и данные отправляются в базу отдельно, и никакой пользовательский ввод уже не может изменить структуру запроса. Вот, смотри, как надо:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=:username AND password=:password");
$stmt->execute(['username' => $username, 'password' => $password]);

Вот это — надёжно. Запрос уже скомпилирован, места для подстановки чётко обозначены, и туда никакую левую хуйню не воткнуть.

  1. Валидируй и экранируй ввод. Но это, честно, уже второй эшелон. Подготовленные выражения — главное оружие.
  2. Принцип минимальных привилегий для БД. Не заводи от имени приложения суперпользователя, который может всё. Дай ему права только на SELECT, INSERT, UPDATE в нужных таблицах. Пусть даже если его как-то взломают, он не сможет наделать делов — дропнуть базу или всю схему переписать. Это как не давать гостю ключи от сейфа, а только от туалета.

Короче, чувак, если будешь тупо склеивать строки для SQL — ты ходишь по охуенно тонкому льду. Рано или поздно провалишься. Используй подготовленные выражения, и спи спокойно.