SQL Injection у мобільній розробці: що це таке, методи атак та захист

Автор: IT Sectr Опубліковано: 2026-04-06 Час читання: 9 хв

SQL Injection — тип атаки на базу даних додатку, при якій зловмисник впроваджує шкідливий SQL-код у параметри запиту, отримуючи несанкціонований доступ до даних або можливість їх модифікації. За даними OWASP (2025), SQL Injection залишається однією з критичних вразливостей, здатної призвести до повної компрометації бази даних. Ін'єкція SQL-коду дозволяє зловмиснику читати, змінювати та видаляти записи, а в деяких випадках — отримати доступ до операційної системи сервера.

Головне

  • SQL Injection — впровадження SQL-коду через користувацькі параметри, що змінює логіку запиту до бази даних
  • Параметризація запитів — основний метод захисту: відокремлення SQL-коду від даних за допомогою prepared statements
  • Типи атак — класична ін'єкція (впровадження через WHERE), Blind SQLi (логічні висновки), UNION-based (читання чужих таблиць)
  • Error-based SQLi — вилучення даних через повідомлення про помилки бази даних
  • ORM-фреймворки — знижують ризик SQLi при правильному використанні, але не усувають його повністю

Що таке SQL Injection?

SQL Injection — це вразливість, що виникає, коли додаток формує SQL-запит шляхом конкатенації рядків з користувацькими даними. Зловмисник передає в параметр запиту спеціально сконструйований рядок, який змінює структуру SQL-команди. Замість того щоб бути даними, введений рядок стає частиною SQL-коду, що дозволяє атакуючому виконувати довільні запити до бази даних. За даними Verizon Data Breach Report (2025), SQL Injection присутній у 8% усіх досліджених витоків даних.

Чому SQL Injection досі актуальний?

Незважаючи на відомість вразливості (перші згадки — кінець 1990-х), SQL Injection зустрічається в сучасних додатках. Причина — людський фактор: розробники допускають конкатенацію рядків у коді, legacy-код не рефакториться, а ORM-фреймворки використовуються неправильно (наприклад, raw-запити з підстановкою значень через рядки). За даними Veracode (2026), близько 14% усіх просканованих додатків містять хоча б одну SQLi-вразливість.

Що може зробити зловмисник?

Успішна SQL Injection дає атакуючому широкий спектр можливостей: читання будь-яких таблиць бази даних, включаючи хеші паролів та персональні дані користувачів; модифікація та видалення записів; виконання адміністративних операцій (DROP TABLE, TRUNCATE); у деяких конфігураціях — віддалене виконання команд через xp_cmdshell (MSSQL) або INTO OUTFILE (MySQL). Наслідки — від витоку користувацьких даних до повної втрати контролю над системою.

Типи SQL-ін'єкцій

SQL-ін'єкції класифікуються за способом вилучення даних з бази даних. Вибір методу залежить від того, як додаток обробляє результати запиту та повідомлення про помилки. Класифікація OWASP виділяє три основні типи: In-band (дані вилучаються через той самий канал), Inferential/Blind (логічні висновки) та Out-of-band (дані передаються через інший канал).

ТипСпосіб вилучення данихСкладністьЧастота
In-band (класичний)Безпосередньо через результат запитуНизькаВисока
Blind SQLiЛогічні висновки за відповідями сервераВисокаСередня
Out-of-bandЧерез зовнішній канал (DNS, HTTP)СередняНизька

In-band SQL Injection (класична)

Найпоширеніший тип. Зловмисник впроваджує SQL-код у параметр запиту, і результат впровадження видно безпосередньо у відповіді сервера. Два підвиди: Error-based (через повідомлення про помилки БД) та UNION-based (через оператор UNION SELECT). Error-based використовує інформацію з повідомлень про помилки, наприклад, синтаксичну помилку MySQL, яка може розкрити ім'я таблиці або структуру запиту. UNION-based дозволяє об'єднати результати легітимного запиту з даними з інших таблиць бази даних.

Blind SQL Injection (сліпа)

Використовується, коли додаток не відображає результати запиту або повідомлення про помилки. Зловмисник задає питання типу «так/ні», відправляючи запити з логічними умовами та аналізуючи різницю у відповіді сервера (наприклад, за часом відгуку або вмістом сторінки). Time-based Blind SQLi використовує функцію затримки (SLEEP, WAITFOR DELAY) для підтвердження умов — якщо сторінка завантажується довше, умова істинна. Цей метод дуже повільний — вилучення одного запису може зайняти години.

python
# Приклад Blind SQL Injection (time-based)
# Якщо SQLi вразливий, SLEEP(2) виконується за умови
import requests
import time

payload = "' OR IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a',SLEEP(2),0) -- "
url = "http://example.com/user?id=1" + payload

start = time.time()
response = requests.get(url)
elapsed = time.time() - start

# Якщо відповідь прийшла через >2 секунди — перша літера пароля 'a'
print(f"Time: {elapsed:.2f}s - First letter is 'a'" if elapsed > 2 else "First letter is not 'a'")

Out-of-band SQL Injection

Дані передаються не через HTTP-відповідь, а через альтернативні канали: DNS-запити, HTTP-запити на зовнішній сервер, SMTP. Використовується, коли додаток не повертає результати запиту та не показує помилок. MySQL підтримує функцію LOAD_FILE(), яка може ініціювати DNS-запит, а MSSQL — xp_dirtree для відправки даних на віддалений SMB-сервер. Out-of-band SQL Injection ефективний, але вимагає додаткових налаштувань на сервері зловмисника та наявності певних функцій БД.

Як працює SQL-ін'єкція?

Механізм SQL Injection заснований на тому, що SQL використовує лапки для рядкових літералів. Якщо додаток підставляє користувацьке введення безпосередньо в SQL-запит без екранування, зловмисник може «закрити» рядок і додати довільний SQL-код. Наприклад, у запиті SELECT * FROM users WHERE name = '$input' підстановка ' OR '1'='1 перетворює запит на SELECT * FROM users WHERE name = '' OR '1'='1', що повертає всіх користувачів.

Класичний приклад: обхід автентифікації

Розглянемо форму логіну із запитом SELECT * FROM users WHERE username = '$user' AND password = '$pass'. Якщо зловмисник вводить у поле username admin' -- , а пароль залишає порожнім, результуючий запит стає SELECT * FROM users WHERE username = 'admin' -- ' AND password = ''. Символи -- коментують решту запиту, і умова перевірки пароля відключається. Сервер повертає запис користувача admin, і зловмисник входить у систему без знання пароля.

python
# Приклад SQL Injection — обхід автентифікації
# ВРАЗЛИВИЙ КОД: пряма конкатенація рядків
def login_vulnerable(username, password):
    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    cursor.execute(query)
    return cursor.fetchone() is not None

# username = "admin' --" обнуляє перевірку пароля
# БЕЗПЕЧНА ВЕРСІЯ: параметризований запит
def login_secure(username, password):
    query = "SELECT * FROM users WHERE username = %s AND password = %s"
    cursor.execute(query, (username, password))
    return cursor.fetchone() is not None

UNION-based: читання чужих таблиць

Оператор UNION SELECT дозволяє об'єднати результати двох SELECT-запитів. Якщо зловмисник знаходить вразливий параметр, він додає UNION SELECT із запитом з іншої таблиці. Наприклад: ' UNION SELECT username, password FROM admins --. Умова успіху — кількість колонок в обох запитах має збігатися. Кількість колонок визначається через ORDER BY (підстановка ' ORDER BY 1--, потім 2, 3... до помилки). Знаючи кількість колонок, зловмисник підставляє UNION SELECT з такою ж кількістю полів.

SQL Injection у мобільних додатках

Мобільні додатки стикаються з SQL Injection як на серверній стороні (API), так і на клієнті — у локальних базах даних (SQLite, Realm). Хоча ризик серверної SQLi в мобільному API аналогічний веб-додаткам, локальна БД створює додатковий вектор. Якщо додаток зберігає дані в SQLite та виконує запити з конкатенацією рядків, шкідливі дані, що потрапили в локальну БД через API, можуть викликати SQLi при подальшій обробці.

SQL Injection в SQLite на Android/iOS

Локальна SQLite-база на пристрої також вразлива до SQL Injection, якщо додаток формує запити конкатенацією рядків. Content Providers на Android та Core Data на iOS використовують параметризацію за замовчуванням, але raw-запити вимагають уваги розробника. SQLite не підтримує множинні запити через крапку з комою, що обмежує можливості зловмисника, але не захищає від читання даних через WHERE-умови. Завжди використовуйте selectionArgs в Android та NSPredicate з параметрами в iOS.

SQL Injection через API мобільного додатку

API, до якого звертається мобільний додаток, вразливий так само, як будь-який веб-сервер. Мобільні розробники часто вважають, що SQLi — проблема тільки бекенду, але вразливість виникає на рівні API-ендпоінта, який приймає параметри від клієнта. Розділення відповідальності не захищає: якщо бекенд-розробник забув параметризувати запит, мобільний додаток користувача стає вектором атаки. Вимагайте від бекенду використання ORM або prepared statements.

kotlin
// Приклад SQL Injection в локальній SQLite на Android
// ВРАЗЛИВИЙ КОД: пряма конкатенація
fun getUserVulnerable(db: SQLiteDatabase, userId: String): Cursor {
    return db.rawQuery(
        "SELECT * FROM users WHERE id = $userId", null
    )
}

// БЕЗПЕЧНА ВЕРСІЯ: параметризація через selectionArgs
fun getUserSecure(db: SQLiteDatabase, userId: String): Cursor {
    return db.rawQuery(
        "SELECT * FROM users WHERE id = ?",
        arrayOf(userId)
    )
}

Методи запобігання SQL-ін'єкціям

Захист від SQL Injection будується на простому принципі: ніколи не довіряйте користувацькому введенню в SQL-запитах. Єдиний надійний метод — параметризація запитів (prepared statements), при якій SQL-код та дані передаються окремо. Всі інші методи — екранування, валідація, WAF — є додатковими шарами захисту, але не замінюють параметризацію. За даними OWASP (2025), параметризація запобігає 100% SQL Injection-атак.

Prepared Statements (параметризовані запити)

При використанні prepared statements SQL-запит спочатку компілюється сервером БД без даних, а потім значення параметрів передаються окремо. База даних розглядає параметри як дані, а не як виконуваний код. Навіть якщо зловмисник передасть ' OR '1'='1, БД інтерпретує це як рядкове значення, а не як SQL-код. Prepared statements підтримуються всіма сучасними мовами та фреймворками: PDO в PHP, PreparedStatement в Java, cursor.execute в Python.

ORM-фреймворки та Query Builders

Сучасні ORM (Hibernate, Entity Framework, SQLAlchemy, Room) автоматично використовують параметризацію при виконанні запитів, якщо розробник не переходить на raw-запити. Однак ORM не захищають повністю: конструкції на кшталт @Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true) в JPA вимагають передачі параметрів через named parameters, а не конкатенації. Query Builders (Knex, jOOQ) також параметризують запити за замовчуванням, якщо не використовувати raw-методи.

Екранування рядків (не рекомендується як основний метод)

Екранування спецсимволів (mysql_real_escape_string) — застарілий метод, який не захищає від усіх типів SQL Injection. Проблема: екранування залежить від кодування та може бути обійдене при використанні багатобайтових кодувань (наприклад, GBK в азійських системах). Використовуйте екранування тільки в legacy-коді, де параметризація неможлива, і завжди в комбінації з суворою валідацією типу вхідних даних.

МетодЕфективністьРекомендація
Prepared Statements100%Обов'язково для всіх запитів
ORM (правильне використання)99%Рекомендується
Екранування рядків70% (залежить від кодування)Тільки legacy
Валідація введення (white-list)50% (тільки для чисел)Додатково
WAF (Web Application Firewall)60%Додатково

Принцип найменших привілеїв для БД

Обліковий запис додатку повинен мати мінімально необхідні права: SELECT, INSERT, UPDATE, DELETE — тільки на ті таблиці, які реально потрібні додатку. Забороніть використання DROP, TRUNCATE, CREATE для прикладного облікового запису. Це обмежить збитки навіть у разі успішної SQL Injection: зловмисник не зможе видалити таблиці або виконати адміністративні операції.

Інструменти для виявлення SQL-ін'єкцій

Регулярне тестування на SQL Injection має бути частиною пайплайну безпечної розробки. Комбінація статичного аналізу, динамічного сканування та ручного пентесту дає найкращі результати. За даними Synopsys Cybersecurity Report (2025), автоматичні сканери знаходять до 70% SQLi-вразливостей, однак складні Blind-атаки вимагають ручного тестування.

  • sqlmap — найпопулярніший інструмент для автоматичного виявлення та експлуатації SQL Injection
  • OWASP ZAP — безкоштовний DAST-сканер з модулями активного сканування SQLi
  • Burp Suite Scanner — професійний інструмент з автоматичним детектуванням SQL Injection
  • SonarQube — статичний аналіз коду на вразливості, включаючи SQLi-патерни
  • CodeQL — семантичний аналіз коду для пошуку SQL-ін'єкцій у вихідних кодах

Для мобільних додатків важливий і аналіз локального SQLite: перевірте всі rawQuery-виклики, ContentProvider-запити та Room-запити з rawQuery. Інструменти: Android Studio Lint (детектує SQLi в SQLite), MobSF (Mobile Security Framework) для автоматичного статичного та динамічного аналізу APK/IPA. Рекомендується також тестувати API-ендпоінти через sqlmap з проксі-перехопленням трафіку мобільного додатку.

Часті запитання

В чому різниця між SQL Injection та NoSQL Injection?

SQL Injection атакує реляційні бази даних через SQL-запити. NoSQL Injection впливає на нереляційні БД (MongoDB, Couchbase) через їх оператори запитів ($gte, $ne, $where). У MongoDB ін'єкція можлива, якщо додаток формує BSON-документ з рядка JSON. Механізми захисту аналогічні: параметризація та валідація типів.

Як виявити SQL Injection в коді самостійно?

Знайдіть всі місця, де SQL-запити формуються через конкатенацію рядків з користувацькими даними. Шукайте патерни виду "SELECT ... WHERE id = " + userId або f"UPDATE ... SET name = '{name}'". Кожен такий рядок — потенційна SQL-ін'єкція. Замініть всі на параметризовані запити або prepared statements.

Чи захищає ORM від SQL Injection автоматично?

ORM-фреймворки захищають автоматично, тільки якщо ви використовуєте їх методи Query Builder та named parameters. Якщо ви використовуєте raw-запити (nativeQuery в JPA, rawQuery в Room), захист не працює — необхідно передавати параметри через підготовлені вирази, а не через конкатенацію рядків.

Що таке Second-Order SQL Injection?

Second-Order SQL Injection — атака, при якій шкідливі дані зберігаються в БД як безпечні, але потім використовуються в іншому запиті без екранування. Наприклад, зловмисник реєструється з username ' OR '1'='1. Дані зберігаються як рядок — при реєстрації атаки немає. Але якщо інший запит підставляє username в SQL без параметризації, ін'єкція спрацьовує.

Чи може NoSQL Injection бути небезпечнішим за SQL Injection?

NoSQL Injection потенційно небезпечніший через меншу обізнаність розробників. Розробники знають про SQL Injection і більшість використовують ORM, але про NoSQL Injection знають небагато. У MongoDB неправильно сформований запит може повернути всі документи колекції. Захист — ті ж prepared statements (BSON-параметризація) та сувора валідація вхідних даних.

Підсумки

  • SQL Injection — атака впровадженням SQL-коду через неекрановані користувацькі параметри в запитах до БД
  • Основні типи — In-band (класична), Blind (сліпа, за часом), Out-of-band (через зовнішній канал)
  • Параметризація запитів — єдиний 100% надійний метод захисту від SQL Injection
  • Міф про ORM — ORM захищає тільки при використанні вбудованих методів, raw-запити з конкатенацією все ще вразливі
  • Принцип найменших привілеїв — обмеження прав облікового запису БД мінімізує збитки при успішній атаці
  • Регулярне тестування — sqlmap, OWASP ZAP, SonarQube мають бути частиною CI/CD пайплайну
  • Локальна SQLite — мобільні додатки також повинні параметризувати запити до локальної БД

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також