Объясните, как работает SQL-инъекция, почему простая экранировка не всегда спасает, как использовать подготовленные выражения/ORM, какие есть угрозы в NoSQL/ORM-уровне (e.g., injection в MongoDB) и дополнительные меры (валидация, принцип наименьших привилегий, логирование, WAF)
Суть: приложение подставляет небезопасный ввод пользователя напрямую в SQL‑запрос, и злоумышленник формирует такой ввод, что изменяет структуру запроса (логика, фильтры, добавление команд).Пример уязвимого шаблона: SELECT FROM users WHERE username = '...'; Если пользователь вводит: ' OR 1=1 -- то итоговый запрос становится: SELECT FROM users WHERE username = '' OR (1=1) --' и условие (1=1) делает фильтр всегда истинным — чтение всех записей.
Почему простая экранировка не всегда спасает
Контекст‑зависимость: нужны разные правила экранирования для строк, идентификаторов, чисел, LIKE, JSON и т.д.Ошибки реализации: неправильная функция экранирования, несоответствие кодировок (например, многобайтовые кодировки могут обойти простую замену), двойное кодирование/декодирование.Вторичные инъекции (second‑order): данные безопасно сохранены, но позже используются в другом контексте без обработок.Разные СУБД и расширения имеют свои «особые» синтаксисы и операторы — стандартного экранирования может не хватить.Если конструируется SQL идентификатор (имя таблицы/колонки) — параметризация обычно не поддерживается; экранирование здесь сложнее и рискованней.
Как работают подготовленные выражения и почему они защищают
Идея: структура запроса отправляется СУБД отдельно от данных; данные передаются как параметры, СУБД не объединяет их в SQL‑код.Защита: параметры трактуются только как данные, даже если содержат кавычки или SQL‑фрагменты.Примеры: PHP PDO: stmt=stmt = stmt=pdo->prepare("SELECT * FROM users WHERE email = ?"); $stmt->execute([$email]);Python (psycopg2): cur.execute("SELECT * FROM users WHERE id = %s", (id,))ORM (SQLAlchemy): session.query(User).filter(User.name == user_input).first()Ограничение: параметры защищают только данные, а не динамически подставляемые части SQL (имена таблиц, ORDER BY, LIMIT без параметров). Для таких случаев нужно верифицировать/беллистить значения.
Угрозы в NoSQL и на уровне ORM (примеры для MongoDB и JS)
MongoDB «инъекции» через JSON‑параметры: Уязвимый код: db.users.find({ username: userInput })Если userInput = { "$ne": null } или { "$gt": "" } — фильтр изменится и может вернуть всё.$where и JavaScript‑инъекции: использование строк с JS в запросах позволяет выполнять произвольный код.Прототипная «pollution» / object injection: в JS‑стеке слияние объектов (например, _.merge) может привести к подмене неожиданных полей (например, proto, constructor).ORM‑уровень: многие ORM автоматически параметризуют, но опасность — использование raw SQL или конкатенация в .filter() / .order_by() с пользовательскими строками. Также миграции/функции генерации запросов могут внедрять необработанные значения.Защиты в NoSQL: валидировать типы/формат входа, использовать строгие схемы (например, MongoDB jsonSchema),запрещатьjsonSchema), запрещать jsonSchema),запрещатьwhere и запрещать операторы в пользовательских полях.
Дополнительные меры безопасности
Валидация и белый список: строгая проверка типов, длины, формата; для динамических частей (ORDER BY, column) — только заранее разрешённые значения.Принцип наименьших привилегий: аккаунт БД должен иметь только нужные привилегии (SELECT/INSERT только по нужным таблицам, без DROP/ALTER если не нужно).Логирование и мониторинг: логирование ошибок и подозрительной активности, алерты на аномальные запросы или частые ошибки аутентификации.WAF (web application firewall): дополнительный уровень, который может блокировать известные паттерны SQLi/NoSQLi, но не заменяет безопасную архитектуру.Параноидальные правила: ограничение длины входа, rate limiting, использование CAPTCHА для критичных форм.Регулярное тестирование: периодические pentest/DAST/SAST, использование автоматических сканеров на SQLi, код‑ревью.Обновления и патчи: поддерживать СУБД, драйверы и ORM в актуальном состоянии.Защитные шаблоны: избегать конкатенации SQL, использовать ORM/параметры, не хранить секреты в коде, применять контейнеризацию/изоляцию для БД.
Короткие практические правила
Всегда использовать параметризованные запросы/подготовленные выражения вместо ручной подстановки.Валидировать и беллистить входы; преобразовывать к нужному типу на сервере.Не доверять ORM «по умолчанию» при использовании сырого SQL — ревью всех raw‑запросов.Ограничить права БД и вести логирование; использовать WAF и регулярные тесты.
Это основные принципы и практики, которые защищают от SQL/NoSQL‑инъекций и снижают риски на уровне ORM и инфраструктуры.
Как работает SQL‑инъекция
Суть: приложение подставляет небезопасный ввод пользователя напрямую в SQL‑запрос, и злоумышленник формирует такой ввод, что изменяет структуру запроса (логика, фильтры, добавление команд).Пример уязвимого шаблона:SELECT FROM users WHERE username = '...';
Если пользователь вводит: ' OR 1=1 --
то итоговый запрос становится: SELECT FROM users WHERE username = '' OR (1=1) --'
и условие (1=1) делает фильтр всегда истинным — чтение всех записей.
Почему простая экранировка не всегда спасает
Контекст‑зависимость: нужны разные правила экранирования для строк, идентификаторов, чисел, LIKE, JSON и т.д.Ошибки реализации: неправильная функция экранирования, несоответствие кодировок (например, многобайтовые кодировки могут обойти простую замену), двойное кодирование/декодирование.Вторичные инъекции (second‑order): данные безопасно сохранены, но позже используются в другом контексте без обработок.Разные СУБД и расширения имеют свои «особые» синтаксисы и операторы — стандартного экранирования может не хватить.Если конструируется SQL идентификатор (имя таблицы/колонки) — параметризация обычно не поддерживается; экранирование здесь сложнее и рискованней.Как работают подготовленные выражения и почему они защищают
Идея: структура запроса отправляется СУБД отдельно от данных; данные передаются как параметры, СУБД не объединяет их в SQL‑код.Защита: параметры трактуются только как данные, даже если содержат кавычки или SQL‑фрагменты.Примеры:PHP PDO:
stmt=stmt = stmt=pdo->prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);Python (psycopg2):
cur.execute("SELECT * FROM users WHERE id = %s", (id,))ORM (SQLAlchemy):
session.query(User).filter(User.name == user_input).first()Ограничение: параметры защищают только данные, а не динамически подставляемые части SQL (имена таблиц, ORDER BY, LIMIT без параметров). Для таких случаев нужно верифицировать/беллистить значения.
Угрозы в NoSQL и на уровне ORM (примеры для MongoDB и JS)
MongoDB «инъекции» через JSON‑параметры:Уязвимый код: db.users.find({ username: userInput })Если userInput = { "$ne": null } или { "$gt": "" } — фильтр изменится и может вернуть всё.$where и JavaScript‑инъекции: использование строк с JS в запросах позволяет выполнять произвольный код.Прототипная «pollution» / object injection: в JS‑стеке слияние объектов (например, _.merge) может привести к подмене неожиданных полей (например, proto, constructor).ORM‑уровень: многие ORM автоматически параметризуют, но опасность — использование raw SQL или конкатенация в .filter() / .order_by() с пользовательскими строками. Также миграции/функции генерации запросов могут внедрять необработанные значения.Защиты в NoSQL: валидировать типы/формат входа, использовать строгие схемы (например, MongoDB jsonSchema),запрещатьjsonSchema), запрещать jsonSchema),запрещатьwhere и запрещать операторы в пользовательских полях.
Дополнительные меры безопасности
Валидация и белый список: строгая проверка типов, длины, формата; для динамических частей (ORDER BY, column) — только заранее разрешённые значения.Принцип наименьших привилегий: аккаунт БД должен иметь только нужные привилегии (SELECT/INSERT только по нужным таблицам, без DROP/ALTER если не нужно).Логирование и мониторинг: логирование ошибок и подозрительной активности, алерты на аномальные запросы или частые ошибки аутентификации.WAF (web application firewall): дополнительный уровень, который может блокировать известные паттерны SQLi/NoSQLi, но не заменяет безопасную архитектуру.Параноидальные правила: ограничение длины входа, rate limiting, использование CAPTCHА для критичных форм.Регулярное тестирование: периодические pentest/DAST/SAST, использование автоматических сканеров на SQLi, код‑ревью.Обновления и патчи: поддерживать СУБД, драйверы и ORM в актуальном состоянии.Защитные шаблоны: избегать конкатенации SQL, использовать ORM/параметры, не хранить секреты в коде, применять контейнеризацию/изоляцию для БД.Короткие практические правила
Всегда использовать параметризованные запросы/подготовленные выражения вместо ручной подстановки.Валидировать и беллистить входы; преобразовывать к нужному типу на сервере.Не доверять ORM «по умолчанию» при использовании сырого SQL — ревью всех raw‑запросов.Ограничить права БД и вести логирование; использовать WAF и регулярные тесты.Это основные принципы и практики, которые защищают от SQL/NoSQL‑инъекций и снижают риски на уровне ORM и инфраструктуры.