SQL-ін'єкція - коли дані від користувача потрапляють у текст SQL-запиту й змінюють його структуру.
// Вразливо
$sql = "SELECT * FROM users WHERE email = '" . $_GET['email'] . "'";
// email = ' OR '1'='1 → WHERE email = '' OR '1'='1' → усі користувачі
Наслідки - від читання чужих даних і обходу входу до видалення таблиць і, в окремих конфігураціях, виконання команд на сервері.
Захист - підготовлені запити (prepared statements): структура запиту й дані передаються в базу окремо. База спершу розбирає SQL із заповнювачами, а значення підставляє вже як дані - вони не можуть стати частиною синтаксису.
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
User::where('email', $email)->first(); // Eloquent і Query Builder роблять те саме
Де помиляються навіть з ORM:
- Сирі вирази з конкатенацією:
whereRaw("email = '$email'"),DB::select("... $id"). Сирий SQL - лише з прив'язками:whereRaw('lower(email) = ?', [$email]). - Імена колонок і напрямок сортування не можна передати заповнювачем.
orderBy($request->input('sort'))- звіряти з білим списком дозволених значень. LIKE- заповнювач захищає від ін'єкції, але%і_у введенні все одно працюють як шаблони; їх треба екранувати, якщо це важливо.
Додатково: користувач бази для застосунку з мінімальними правами (без DROP, без доступу до чужих баз) - щоб навіть успішна ін'єкція мала обмежені наслідки.