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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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