LIVE: New phishing campaigns targeting mobile users —View latest threats →

Back to Tutorials
Просунутий 14 хв читання

SQL-ін'єкція: як це працює і як це зупинити

SQL-ін'єкція залишається серед найбільш використовуваних вразливостей. Дивіться, як атака витягує дані бази і вивчіть ефективні засоби захисту, які її зупиняють.

10 січня 2026 р.

Чому SQL-ін'єкція досі існує

SQL-ін'єкція була вперше задокументована у 1998 році. Вона фігурує в кожному списку OWASP Top 10 з моменту його заснування. Вона стала причиною деяких найбільших витоків даних в історії — TalkTalk (4 мільйони записів), Heartland Payment Systems (130 мільйонів номерів карток) та незліченна кількість інших.

Причина її існування не в складності. SQL-ін'єкція є простою для розуміння і, що критично, простою для запобігання. Вона зберігається тому, що розробники конкатенують дані користувача в SQL-запити, не замислюючись про наслідки, часто під тиском часу і без навчання з безпеки.

Цей підручник показує точно, як це працює, і конкретні техніки, що її усувають.

Як зазвичай працює SQL-запит

Розглянемо форму входу. Застосунок приймає ім'я користувача та пароль і перевіряє їх у базі даних:

SELECT * FROM users WHERE username = 'alice' AND password = 'secretpass';

Якщо запит повертає рядок, користувач автентифікований. Це нормальна і очікувана поведінка.

Вразливість виникає, коли розробник будує цей запит шляхом конкатенації рядків безпосередньо з введених користувачем даних:

# Вразливий код Python
query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';"

Припущення полягає в тому, що користувачі вводитимуть нормальні значення. Зловмисники — ні.

Атака: вихід за межі рядка

SQL використовує одинарні лапки для розмежування рядкових значень. Якщо зловмисник вводить ім'я користувача, що містить одинарну лапку, він може вийти за межі передбаченого рядка та впровадити власний SQL.

Введення зловмисника:

  • Ім'я користувача: ' OR '1'='1
  • Пароль: будь-що

Результуючий запит:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'будь-що';

Оскільки OR '1'='1' завжди є істинним, цей запит повертає всіх користувачів. Вхід виконується для першого користувача в базі даних, як правило адміністратора.

Повний обхід перевірки пароля:

  • Ім'я користувача: admin'--
  • -- є коментарем SQL; все після нього ігнорується
SELECT * FROM users WHERE username = 'admin'--' AND password = 'будь-що';
-- Стає:
SELECT * FROM users WHERE username = 'admin';

Автентифікація обходиться. Поле пароля ніколи не перевіряється.

Понад автентифікацію: видобування даних

SQL-ін'єкція не обмежується обходом автентифікації. Більш серйозні атаки видобувають дані з усієї бази даних.

UNION-based ін'єкція

Оператор SQL UNION об'єднує результати двох операторів SELECT. Зловмисник може використати його для отримання даних з інших таблиць:

-- Оригінальний запит
SELECT name, description FROM products WHERE id = 1;

-- Впроваджений
SELECT name, description FROM products WHERE id = 1
UNION SELECT username, password FROM users--;

Це додає всі імена користувачів і паролі до результатів продуктів, що повертаються зловмиснику.

Сліпа SQL-ін'єкція

Багато застосунків не відображають помилки бази даних або результати запитів користувачам. Сліпа SQL-ін'єкція видобуває дані по одному біту, задаючи питання «так/ні»:

-- Чи є першим символом пароля адміністратора 'a'?
SELECT * FROM users WHERE id = 1 AND SUBSTRING(password, 1, 1) = 'a';

Якщо сторінка поводиться по-різному залежно від того, чи є умова істинною чи хибною, зловмисник може зробити висновок про відповідь. Автоматизовані інструменти на кшталт sqlmap можуть видобути цілі бази даних через сліпу ін'єкцію за лічені хвилини.

Позаканальні та складені запити

На деяких системах баз даних зловмисники можуть:

  • Виконувати кілька операторів (складені запити): видаляти таблиці, створювати бекдор-облікові записи
  • Читати файли з файлової системи сервера (LOAD_FILE() у MySQL)
  • Записувати файли на сервер (потенційно створюючи вебшелл)
  • Ініціювати мережеві з'єднання для позаканального виведення даних

SQL-ін'єкція в найгіршому випадку означає повний злом сервера, а не лише витік даних.

Засоби захисту, що дійсно працюють

Захист 1: Параметризовані запити (підготовлені вирази)

Це основний захист, і він усуває SQL-ін'єкцію, а не просто зменшує її.

З параметризованим запитом код SQL і дані надсилаються до бази даних окремо. База даних спочатку компілює шаблон SQL, а потім прив'язує значення, введені користувачем. Значення ніколи не можуть бути інтерпретовані як SQL — вони завжди розглядаються як дані.

Python з параметризованим запитом:

# Безпечно
cursor.execute(
    "SELECT * FROM users WHERE username = %s AND password = %s",
    (username, password)
)

Java з PreparedStatement:

PreparedStatement stmt = conn.prepareStatement(
    "SELECT * FROM users WHERE username = ? AND password = ?"
);
stmt.setString(1, username);
stmt.setString(2, password);

Незалежно від того, що користувач вводить у поле username — включаючи ' OR '1'='1 — це розглядається як літеральне рядкове значення, а не SQL. Ін'єкція є неможливою.

Захист 2: ORM та конструктори запитів

Об'єктно-реляційні маппери (ORM) на кшталт SQLAlchemy, Hibernate, ActiveRecord і Django ORM використовують параметризовані запити внутрішньо. Правильне використання ORM запобігає SQL-ін'єкції майже у всіх випадках:

# Django ORM — безпечно
User.objects.filter(username=username, password=password)

Увага: більшість ORM мають виходи для сирого SQL (raw(), execute()), які знову вводять ризик ін'єкції, якщо дані користувача конкатенуються. Ставтеся до методів сирого SQL з тією ж обережністю, що й до ручного побудови запитів.

Захист 3: Збережені процедури

Збережені процедури можуть бути безпечними при правильній реалізації — вони мають використовувати параметризовані введення внутрішньо. Збережена процедура, що конкатенує рядки внутрішньо, все одно є вразливою.

Захист 4: Принцип найменших привілеїв

Обліковий запис бази даних, що використовується вебзастосунком, повинен мати лише необхідні дозволи:

  • Застосунок, що переважно читає, потребує лише SELECT
  • Жоден застосунок не повинен запускатися як root, sa або DBA
  • Різні компоненти застосунку можуть використовувати різні облікові записи бази даних із різними дозволами

Це обмежує вплив успішної ін'єкції: зловмисник, який може лише виконувати SELECT, не може видаляти таблиці або записувати файли.

Захист 5: Валідація введення

Перевіряйте, що введені дані відповідають очікуваному формату:

  • Ідентифікатор користувача має бути позитивним цілим числом — відхиляйте все інше до того, як воно досягне запиту
  • Назва продукту не повинна містити ключових слів SQL — застосовуйте список дозволених символів

Валідація введення є заходом глибинного захисту, а не основним контролем. Вона зменшує поверхню атаки, але не повинна бути єдиним захистом.

Захист 6: WAF (файрвол вебзастосунків)

WAF може виявляти та блокувати поширені шаблони SQL-ін'єкцій. Це додатковий шар, а не замінник параметризованих запитів. WAF можна обійти за допомогою обфускації та трюків кодування. Не покладайтеся на них як на єдиний захист.

Тестування на SQL-ін'єкцію

Основи ручного тестування:

  1. Вводьте одинарну лапку (') у кожне поле введення — повідомлення про помилки бази даних часто виявляють точки ін'єкції
  2. Спробуйте 1=1 та 1=2 у числових параметрах і порівняйте відповіді
  3. Спробуйте '; SELECT SLEEP(5);-- — якщо відповідь затримується, присутня сліпа ін'єкція

Автоматизовані інструменти:

  • sqlmap — стандартний інструмент для виявлення та експлуатації (тільки для систем, авторизованих для тестування)
  • Burp Suite — перехоплення та маніпуляція запитами; має сканер SQL-ін'єкцій у версії Pro
  • OWASP ZAP — безкоштовний сканер з виявленням SQL-ін'єкцій

Контрольний список усунення

  • Замінити всю конкатенацію рядків у запитах до бази даних параметризованими запитами
  • Провести аудит усіх викликів сирого SQL у коді ORM
  • Застосувати облікові записи бази даних із найменшими привілеями
  • Увімкнути придушення помилок бази даних у продакшн (помилки розкривають інформацію про схему)
  • Переглянути та протестувати збережені процедури
  • Додати правила WAF як додатковий шар
  • Запускати sqlmap або аналог у тестовому середовищі перед кожним випуском

SQL-ін'єкція має повне, добре зрозуміле виправлення. Немає причин для її появи в новому коді. Єдиною перешкодою є обізнаність і дисципліна під час розробки.

#SQL injection#web security#OWASP#secure coding#databases