SQL-инъекция, или SQL Injection, — класс уязвимостей, возникающий, когда приложение небезопасно объединяет пользовательские данные с SQL-командами. В результате введенное пользователем значение может начать восприниматься базой данных не только как данные, но и как часть структуры запроса.
Последствия зависят от конкретного приложения и прав учетной записи Database. Уязвимость может привести к чтению чужих записей, изменению данных, обходу части проверок, удалению информации или выполнению других нежелательных операций.
Основная причина SQL-инъекции — смешивание SQL-кода и недоверенных данных. Главный способ защиты — передавать пользовательские значения в запрос как параметры, а не собирать SQL строковой конкатенацией.
Что такое SQL-инъекция простыми словами
Приложению необходимо получить запись пользователя по введенному идентификатору.
Безопасная логика должна разделять команду и данные:
SQL command + parameter value ↓ Database driver
Проблема возникает, если разработчик формирует весь Query как одну строку:
SQL fragment + user input + SQL fragment
Тогда специальные символы во вводе могут изменить синтаксический смысл итогового запроса.
Почему называется инъекцией
Слово Injection означает внедрение. Недоверенные данные внедряются в контекст языка SQL и начинают влиять на выполняемую команду.
Аналогичная идея встречается в Command Injection и некоторых других классах уязвимостей.
Что такое SQL
SQL — язык работы с реляционными базами данных. С его помощью приложения:
- получают записи;
- добавляют данные;
- обновляют значения;
- удаляют записи;
- управляют структурой Database.
Если внешний пользователь способен повлиять не только на значения, но и на структуру SQL-команды, возникает Security Risk.
Как появляется SQL-инъекция
Типичная причина — динамическое создание SQL через String Concatenation.
Логически уязвимый подход выглядит так:
query = "SELECT ... WHERE id = " + user_input
Здесь Application не отделяет User Input от SQL Syntax.
Безопасный подход
Вместо этого используется параметризованный запрос:
query = "SELECT ... WHERE id = ?" parameter = user_input
Database Driver получает структуру команды отдельно от значения и обрабатывает Input как Data.
Parameterized Query
Параметризованный запрос — основной механизм защиты от SQL Injection.
Разработчик заранее определяет SQL Structure, а значения передает отдельно через API драйвера.
Prepared Statement
Prepared Statement — подготовленный запрос, в котором параметры отделены от SQL-команды.
Упрощенно:
Prepare SQL structure ↓ Bind parameters ↓ Execute
Это позволяет Database корректно различать SQL Syntax и User Data.
Почему экранирования недостаточно как основной защиты
Ручное добавление Escape Characters сложно реализовать правильно для всех контекстов, кодировок, типов данных и Database Engines.
Ошибки в одном месте возвращают уязвимость.
Поэтому параметризация надежнее ручного String Escaping.
SQL-инъекция и Input Validation
Проверка входных данных полезна, но не должна заменять параметризованные запросы.
Например, поле возраста можно ограничить только целыми числами.
Но даже после Validation код должен использовать безопасный Database API.
Allowlist Validation
Для некоторых значений, которые невозможно передать обычным SQL-параметром, используется список заранее разрешенных вариантов.
Например, Application может разрешать сортировку только по нескольким известным Columns.
Allowed values: name date price
Любое другое значение отклоняется.
Почему нельзя разрешать произвольное имя столбца
Parameters обычно предназначены для Data Values, а не для SQL Identifiers или Keywords.
Если пользователь влияет на имя таблицы, столбца или направление сортировки, эти элементы нужно выбирать из контролируемого Allowlist.
Где может возникнуть SQL-инъекция
Источник недоверенных данных — не только Login Form.
Уязвимыми могут быть:
- Search;
- URL Parameters;
- API Requests;
- Cookies;
- HTTP Headers;
- Imported Files;
- Webhook;
- данные из сторонних сервисов.
Second-order SQL Injection
Иногда вредоносное значение сначала сохраняется в Database как обычные данные.
Позже другое приложение берет его и небезопасно вставляет в новый SQL Query.
Такой сценарий называют Second-order Injection.
Почему внутренним данным тоже нельзя слепо доверять
Запись в Database могла попасть через другой сервис, импорт или скомпрометированный Account.
Поэтому безопасное формирование Query должно применяться независимо от предполагаемого источника строки.
Какие последствия возможны
В зависимости от уязвимости и Permissions Database Account возможны:
- чтение чужих записей;
- обход ограничений выборки;
- изменение информации;
- удаление данных;
- получение структуры Database;
- нарушение работы приложения.
SQL-инъекция и конфиденциальность
Если приложение позволяет произвольно менять логику SELECT Query, злоумышленник может попытаться получить данные, которые обычный пользователь видеть не должен.
Это угрожает Confidentiality.
SQL-инъекция и Integrity
Если Database Account имеет права UPDATE или DELETE, уязвимость потенциально может повлиять на целостность данных.
Поэтому права Database User существенно влияют на Impact.
SQL-инъекция и Availability
Тяжелый Query или удаление критичных данных может нарушить доступность сервиса.
Таким образом, SQL Injection может затрагивать все три базовых свойства Security: Confidentiality, Integrity и Availability.
SQL-инъекция и Authentication
Особенно опасно небезопасно создавать SQL Query для проверки Login и Password.
Authentication Code должен использовать параметризованные запросы, а Password храниться через специализированное хеширование.
SQL-инъекция не должна использоваться для проверки пароля
Database обычно хранит Password Hash, а Application:
- находит пользователя безопасным параметризованным запросом;
- получает сохраненный Password Hash;
- проверяет введенный Password специализированной Password Hashing Function.
SQL-инъекция и хеширование паролей
Хорошее Password Hashing не устраняет SQL Injection.
Даже если Passwords защищены, уязвимый Query может раскрыть другие данные или изменить Database.
SQL-инъекция и Broken Access Control
Это разные классы проблем.
При Broken Access Control Application неправильно проверяет права пользователя.
При SQL Injection пользователь влияет на SQL Command.
Одна система может иметь обе уязвимости одновременно.
SQL-инъекция и ORM
ORM снижает риск, если разработчик использует стандартные безопасные методы Query Builder и Parameters.
Но ORM не гарантирует отсутствие SQL Injection.
Raw SQL в ORM
Опасность возвращается, если Developer начинает вручную собирать Raw SQL из пользовательских строк.
ORM safe API → lower risk Raw concatenated SQL → injection risk
Query Builder
Query Builder формирует SQL программно и обычно параметризует значения автоматически.
При этом динамические Identifiers и специальные Raw Expressions все равно требуют осторожности.
Stored Procedure
Stored Procedure сама по себе не гарантирует безопасность.
Если внутри Procedure динамический SQL формируется через небезопасную конкатенацию, SQL Injection остается возможной.
Безопасные Stored Procedures
Procedure должна принимать параметры и использовать их как Data, а не объединять с SQL Syntax без необходимости.
Dynamic SQL
Dynamic SQL иногда нужен для сложных отчетов или административных функций.
Чем больше частей Query формируются динамически, тем выше требования к Allowlist и параметризации.
Типы SQL-инъекций
SQL Injection можно классифицировать по тому, как Application возвращает результат и каким способом ошибка проявляется.
На высоком уровне встречаются:
- In-band SQL Injection;
- Blind SQL Injection;
- Out-of-band SQL Injection.
In-band SQL Injection
При In-band сценарии результаты воздействия доступны через тот же канал, через который отправлялся Request.
Например, Web Application возвращает необычные Database Errors или лишние данные в Response.
Blind SQL Injection
Blind SQL Injection означает, что приложение не выводит содержимое Database напрямую, но его поведение может меняться в зависимости от результата SQL-условия.
Основной вывод для разработчика — отсутствие подробной SQL Error на экране еще не означает отсутствие Injection.
Out-of-band SQL Injection
В отдельных архитектурах Database может иметь возможность взаимодействовать с внешними системами.
Это увеличивает Potential Impact, поэтому Database Server следует ограничивать в ненужном исходящем Network Access.
Error-based SQL Injection
Подробные Database Errors могут раскрывать структуру Query, названия Tables, Columns и другие технические детали.
Production Application не должно показывать пользователю полный Stack Trace и SQL Error.
Безопасная обработка ошибок
Пользователю возвращается нейтральное сообщение:
Request could not be processed
А технические детали записываются в защищенный Application Log.
Почему скрытие ошибок не устраняет Injection
Отключение подробных сообщений уменьшает утечку информации, но не исправляет небезопасное формирование Query.
Основная проблема должна устраняться в коде.
Least Privilege для Database Account
Application не должно подключаться к Database под Account с максимальными правами без необходимости.
Например, Web Service, которому нужны только операции над определенными Tables, не должен иметь права администрировать всю СУБД.
Почему Database Administrator Account опасен
Если SQL Injection возникает в Application, работающем с чрезмерно привилегированным Database Account, потенциальный Impact существенно возрастает.
Разные Accounts для разных приложений
Несколько сервисов желательно разделять по Database Identities.
Reporting service → read-only account Order service → limited read/write account Migration process → separate privileged account
Это уменьшает Blast Radius.
Read-only Account
Для Reporting Service может быть достаточно SELECT Permissions.
Даже при ошибке в Application такой Account не должен иметь возможности изменять данные.
Database Network Segmentation
Database не должна быть напрямую доступна из Internet, если это не требуется архитектурой.
Обычно соединение разрешено только Application Servers.
Internet → Database : deny Application Server → Database : allow
Firewall и SQL-инъекция
Firewall уменьшает Network Exposure Database, но не предотвращает SQL Injection внутри разрешенного Application Traffic.
Web Application все равно имеет легитимное соединение с Database.
WAF и SQL-инъекция
WAF может обнаруживать часть известных SQL Injection Patterns и блокировать подозрительные HTTP Requests.
Это полезный дополнительный слой защиты.
Почему WAF не заменяет исправление кода
Правила WAF могут давать False Positives и не распознавать все варианты Input.
Корневая защита — безопасный Database Access в самом приложении.
Virtual Patching
Если Legacy Application нельзя быстро исправить, WAF Rule может временно ограничить известные Attack Patterns.
Такое решение должно иметь срок и план устранения Vulnerability в коде.
IDS/IPS и SQL-инъекция
IDS/IPS может обнаруживать известные Network Patterns SQL Injection, если видит соответствующий Traffic.
При HTTPS без TLS Inspection содержимое HTTP Request может быть недоступно Network Sensor.
EDR и SQL-инъекция
EDR обычно не является первым средством Detection SQL Injection, но может увидеть последствия, если эксплуатация приводит к необычной активности Server Process.
SIEM и SQL-инъекция
SIEM может объединить:
WAF SQL injection alert + Application error spike + Database anomaly + EDR event ↓ Security incident
Это помогает определить, была ли атака успешной.
SOC и SQL-инъекция
После Alert SOC проверяет:
- Source IP;
- Target URL;
- какой Parameter вызвал Detection;
- был ли Request заблокирован;
- Application Logs;
- Database Activity;
- последующие действия.
SQL-инъекция и DAST
Dynamic Application Security Testing проверяет работающее приложение и может обнаруживать признаки Injection через контролируемые тестовые запросы.
Такой тест следует выполнять в рамках разрешенного Security Assessment.
SQL-инъекция и SAST
Static Application Security Testing анализирует Source Code и ищет потенциально опасные конструкции, например конкатенацию User Input с SQL Query.
SAST и False Positive
Static Analyzer может отметить код как потенциально уязвимый, хотя Input уже надежно обрабатывается другим компонентом.
Поэтому Findings требуют Code Review.
SQL-инъекция и Code Review
При проверке кода особенно важно искать:
- String Concatenation при создании SQL;
- Raw Query APIs;
- Dynamic SQL;
- ручное Escaping;
- динамические Table и Column Names.
Secure Coding Standard
В команде полезно формально закрепить правило:
All SQL values must use parameter binding
Исключения для динамических Identifiers проходят отдельный Review.
SQL-инъекция в Legacy Code
Старые приложения могут содержать сотни динамических SQL Queries.
Исправление лучше выполнять системно, а не только закрывать один найденный Endpoint.
Как искать похожие проблемы
После обнаружения одного случая необходимо проверить весь Codebase на аналогичный Pattern.
Одинаковый небезопасный Helper Function может использоваться в десятках компонентов.
Root Cause Analysis
Если SQL Injection возникла из-за общего Database Utility, исправление только одного Controller оставит другие уязвимые точки.
Root Cause должен устраняться на уровне общего механизма.
SQL-инъекция и API
REST или GraphQL API не защищены от SQL Injection автоматически.
JSON Input все равно может попасть в SQL Query.
Главное значение имеет способ работы Backend с Database.
GraphQL и SQL-инъекция
GraphQL Schema ограничивает форму запроса API, но Resolver может небезопасно формировать SQL.
Поэтому Backend Security остается обязательной.
SQL-инъекция и микросервисы
Каждый Microservice, работающий с Database, должен самостоятельно использовать безопасные Query APIs.
Наличие API Gateway перед сервисом не исправляет SQL Injection внутри Backend.
SQL-инъекция и Cloud
Перенос приложения в Cloud не устраняет уязвимый код.
Managed Database может улучшить Patch Management и Network Controls, но SQL Injection остается Application-level Problem.
SQL-инъекция и Serverless
Serverless Function также может содержать небезопасный SQL Query.
Модель исполнения не меняет основное правило: Input и SQL Syntax должны быть разделены.
SQL-инъекция и Docker
Container Isolation не защищает Database от Query, который легитимно отправляет уязвимое приложение.
Контейнеризация и Application Security решают разные задачи.
SQL-инъекция и Kubernetes
Kubernetes может ограничивать Network Access и Service Accounts, но уязвимый Application Pod по-прежнему способен отправить нежелательный SQL через разрешенное Database Connection.
SQL-инъекция и Zero Trust
Zero Trust помогает ограничить последствия через Least Privilege и Segmentation, но не заменяет безопасное программирование.
Даже полностью аутентифицированный пользователь может передать вредоносный Input.
SQL-инъекция и RBAC
Application RBAC ограничивает функции пользователя, но SQL Injection может обходить ожидаемую бизнес-логику, если Backend небезопасно формирует Query.
Поэтому Authorization и Query Security должны проверяться независимо.
SQL-инъекция и PAM
PAM защищает Administrative Access к Database, но не предотвращает Injection через обычный Application Account.
Для Database Service Account важнее Least Privilege и безопасные Queries.
SQL-инъекция и DLP
DLP может обнаружить последующий вывод большого объема конфиденциальных данных, но не является основным средством защиты от SQL Injection.
SQL-инъекция и TLS
TLS защищает Query и Response от перехвата по сети.
Но вредоносный Input может быть передан через абсолютно корректное HTTPS-соединение.
Encryption не делает Input безопасным.
SQL-инъекция и CVE
SQL Injection в конкретном публичном продукте может получить CVE Identifier.
Но уязвимость во внутреннем корпоративном приложении обычно выявляется как обычный Security Finding без необходимости публичного CVE.
SQL-инъекция и CVSS
Severity зависит от условий:
- доступен ли Endpoint без Authentication;
- какие данные доступны;
- какие Permissions у Database Account;
- можно ли изменять информацию;
- насколько критична система.
SQL-инъекция и Bug Bounty
SQL Injection является типичным классом уязвимостей, который исследователи могут обнаруживать в рамках разрешенной Bug Bounty Program.
Тестирование должно строго соответствовать Scope и правилам программы.
SQL-инъекция и Pentest
Penetration Testing может проверять наличие Injection контролируемыми методами.
Для Production важно заранее согласовать ограничения, поскольку некоторые тесты способны повлиять на Database Load или Data Integrity.
Почему не стоит тестировать Production без разрешения
Даже проверка предполагаемой Vulnerability может случайно изменить данные или вызвать высокую нагрузку.
Security Testing выполняется только на собственных или явно разрешенных системах.
Логи приложения
Application Logs могут содержать признаки необычного Input и Database Errors.
Но не следует записывать полный Password, Token или другие Secrets только ради диагностики.
Database Audit
Для критичных систем полезно фиксировать административные и необычные Database Actions.
Это помогает расследовать возможные последствия Injection.
Аномалии запросов
Monitoring может обнаружить:
- необычный рост количества SQL Errors;
- резкое увеличение объема возвращаемых данных;
- нетипичные Queries;
- массовые изменения Records;
- необычное время выполнения.
Database Activity Monitoring
Специализированные инструменты могут анализировать Database Sessions и Queries.
Они дополняют Application Security и особенно полезны для высокочувствительных систем.
Rate Limiting
Rate Limiting способен уменьшить скорость автоматизированного перебора и сканирования, но не исправляет SQL Injection.
Один корректно сформированный вредоносный Request может быть достаточен для эксплуатации конкретной Vulnerability.
Почему Blacklist символов не работает надежно
Попытка запретить несколько специальных символов обычно является хрупкой защитой.
SQL имеет сложный синтаксис, разные Database Engines и кодировки.
Надежнее не пытаться угадывать опасные строки, а структурно разделять Code и Data.
Web Application Encoding
HTML Encoding защищает от части XSS-сценариев, но не от SQL Injection.
Для каждого Security Context требуется соответствующая защита.
Context-specific Security
Данные могут проходить через несколько контекстов:
User Input ↓ HTML Application ↓ SQL Database
То, что строка безопасна для HTML, не означает, что ее можно вставлять непосредственно в SQL.
SQL-инъекция и XSS
XSS внедряет нежелательный Script в Web Context, а SQL Injection влияет на Database Query.
Обе проблемы связаны с неправильным разделением данных и исполняемого контекста, но требуют разных защитных механизмов.
SQL-инъекция и Command Injection
Command Injection возникает, когда User Input небезопасно включается в команды операционной системы.
SQL Injection аналогично относится к SQL Language.
Mass Assignment не является SQL-инъекцией
Если API позволяет пользователю изменить запрещенное поле объекта, это другая Application Security Problem.
Не все ошибки работы с Database относятся к Injection.
Типичные ошибки разработчиков
- Собирать SQL через конкатенацию строк.
- Пытаться защищаться только ручным Escaping.
- Считать ORM абсолютной защитой.
- Передавать User Input в Raw SQL.
- Давать Application Account права DBA.
- Показывать подробные SQL Errors пользователю.
- Проверять только Login Form, игнорируя API и Import.
- Считать WAF заменой исправлению кода.
- Доверять данным, ранее сохраненным в Database.
- Не тестировать Dynamic SQL.
Как защититься от SQL-инъекции
Шаг 1. Использовать параметризованные запросы
Это основная защита для всех пользовательских значений.
Шаг 2. Ограничивать динамические Identifiers
Table, Column и Sorting Direction выбираются из Allowlist.
Шаг 3. Применять Least Privilege
Database Account получает только необходимые Permissions.
Шаг 4. Не показывать технические Errors
Подробности остаются в защищенных Logs.
Шаг 5. Использовать SAST и DAST
Автоматические инструменты помогают находить небезопасные места.
Шаг 6. Проводить Code Review
Особое внимание уделяется Raw SQL и Dynamic Query.
Шаг 7. Подключать WAF как дополнительный слой
Особенно для Internet-facing Legacy Applications.
Шаг 8. Мониторить Database и Application
Необычные Queries и Errors должны быть заметны Security Team.
Secure Development Lifecycle
SQL Injection дешевле предотвращать во время разработки, чем исправлять после Incident.
Полезно включить в SDLC:
- Secure Coding Guidelines;
- SAST;
- Dependency Review;
- Code Review;
- DAST;
- Security Testing перед Release.
Unit Tests
Для компонентов Data Access можно создавать тесты, подтверждающие, что специальные User Values обрабатываются как Data и не изменяют Query Structure.
Code Review Checklist
Полезный вопрос для Reviewer:
Can any untrusted value influence SQL structure?
Если ответ положительный, участок требует дополнительного анализа.
Миграция Legacy Application
Если приложение содержит большое количество динамического SQL, безопасная миграция может выполняться поэтапно:
- найти все Raw Query;
- выделить User-controlled Input;
- заменить значения Parameters;
- создать Allowlist для Identifiers;
- уменьшить Database Permissions;
- добавить Security Tests.
Проверка после исправления
Недостаточно изменить строку кода. Следует убедиться, что:
- все похожие Endpoints исправлены;
- Regression Tests проходят;
- не появился функциональный обход;
- Database Permissions соответствуют задаче.
Incident Response при SQL-инъекции
Если есть признаки успешной эксплуатации, процесс может включать:
- ограничение уязвимого Endpoint;
- сохранение Application и Database Logs;
- определение затронутых данных;
- проверку изменений Database;
- смену скомпрометированных Credentials;
- исправление Vulnerability;
- проверку других компонентов с похожим кодом.
Почему простого исправления Query недостаточно после атаки
Если злоумышленник уже изменил данные или получил Credentials, закрытие SQL Injection не отменяет последствий.
Необходимо восстановить доверенное состояние и оценить Data Exposure.
Backup и SQL-инъекция
Backup не предотвращает SQL Injection, но помогает восстановить данные, если они были повреждены или удалены.
При этом важно знать точный момент Incident, чтобы не восстановить уже измененную Database.
Практический пример
Интернет-магазин имеет Endpoint поиска заказов по номеру.
Старая версия приложения вставляет введенное значение непосредственно в SQL String.
Security Review обнаруживает, что User Input может влиять на структуру Query.
Разработчики заменяют код на Parameterized Query.
Before: SQL string + user value After: SQL template + bound parameter
Одновременно Application Database Account лишают ненужных Administrative Permissions, подробные Database Errors скрывают от пользователей, а WAF оставляют как дополнительный Detection Layer.
После изменения команда запускает SAST, DAST и Regression Tests и проверяет другие Endpoints, использующие тот же Data Access Helper.
Так устраняется не только одна найденная точка, но и корневая причина класса уязвимостей.
SQL-инъекция для бизнеса
SQL Injection особенно опасна для систем, где Database содержит клиентские, финансовые, учетные и персональные данные.
Одна ошибка в Internet-facing Application способна поставить под угрозу большой объем информации, поэтому защита должна закладываться в архитектуру приложения, а не добавляться только после Incident.
Для бизнеса важны не только исправления в коде, но и ограничение Database Permissions, Security Testing, WAF, Monitoring и процесс реагирования на возможную компрометацию.
Основные меры защиты
- Parameterized Queries;
- Prepared Statements;
- Allowlist для динамических Identifiers;
- Least Privilege для Database Accounts;
- безопасная обработка Errors;
- SAST и DAST;
- Code Review;
- WAF как дополнительный слой.
Что не следует считать достаточной защитой
- ручное удаление специальных символов;
- одна Blacklist;
- скрытие SQL Error;
- наличие Firewall;
- HTTPS;
- использование ORM без анализа Raw SQL;
- WAF без исправления Application Code.
Связанные термины
| Термин | Связь с SQL-инъекцией |
|---|---|
| SQL | Язык запросов, контекст которого использует Injection |
| Prepared Statement | Разделяет SQL Structure и пользовательские значения |
| ORM | Может автоматически параметризовать Queries |
| WAF | Может блокировать часть известных SQL Injection Patterns |
| IDS/IPS | Может обнаруживать известные сетевые попытки эксплуатации |
| SAST | Ищет опасное формирование SQL в Source Code |
| DAST | Проверяет работающее приложение на Injection |
| Least Privilege | Ограничивает последствия успешной эксплуатации |
| SIEM | Коррелирует WAF, Application и Database Events |
| Broken Access Control | Отдельный класс ошибок Authorization |
| Command Injection | Похожий принцип внедрения данных в другой исполняемый контекст |
| CVE | Публичной SQL Injection в продукте может быть присвоен CVE |
Краткий итог
SQL-инъекция — уязвимость, при которой недоверенные данные начинают влиять на структуру SQL Query. Причиной обычно становится динамическая сборка запросов через конкатенацию строк.
Основная защита — Parameterized Queries и Prepared Statements, которые отделяют SQL Syntax от пользовательских значений. Для динамических имен таблиц, столбцов и других элементов применяют строгий Allowlist.
Дополнительные уровни защиты включают Least Privilege для Database Accounts, WAF, SAST, DAST, Monitoring и безопасную обработку ошибок. Ни Firewall, ни TLS, ни скрытие SQL Error не исправляют уязвимость в коде. Надежная защита должна начинаться с безопасного способа формирования запросов.