История SQL берет свое начало еще в 1990‑х годах, когда приложения стали активно использовать базы данных — и эта практика продолжается по сей день.
В 1979 году компания Oracle разработала поисковый инструмент, который напоминал Excel. Он использовался для работы с данными. Со временем этот инструмент стал языком программирования SQL (Structured Query Language) и теперь повсеместно используется для создания баз данных и разработки сайтов.
Принцип работы SQL-инъекции
SQL востребован практически во всех сферах, с которыми сталкиваются миллионы пользователей по всему миру: от банковского дела до маркетплейсов. Скажем, пользователю в интернет-магазине нужно найти коврик для мыши до 1000 рублей. При поиске нужного товара вручную можно пересмотреть десятки тысяч вариантов, но если воспользоваться фильтрацией и поставить галочки на нужные категории по размеру, цвету и цене, появится подходящий список позиций, который сильно облегчит задачу. Здесь и используется язык запросов SQL.
Когда пользователь ищет нужный ему коврик для мыши, веб‑приложение также выполняет свою работу по поиску и отправляет запросы к базе данных, чтобы искомые товары появились в строке товаров и показались на сайте. Все эти действия происходят незаметно для пользователя — он видит лишь результат своего поиска, который выдает ему веб‑приложение.
Условный запрос, который формирует веб-приложение по фильтрам пользователя, выглядит так:
| sql SELECT * FROM products WHERE category = 'коврик для мыши' AND price < 1000; |
Здесь category и price — значения, которые приходят из формы фильтра на сайте, а не жестко заданы в коде. Проблема в том, что если приложение просто подставляет введенные пользователем данные в текст запроса (конкатенацией строк), вместо цены атакующий может ввести не число, а часть SQL-кода. Например, строка 1000 OR 1=1 превратит запрос в:
| sql SELECT * FROM products WHERE category = 'коврик для мыши' AND price < 1000 OR 1=1; |
Условие 1=1 истинно всегда, поэтому запрос вернет вообще все товары из таблицы, игнорируя фильтр. Это и есть SQL-инъекция: внедрение вредоносного кода в поле ввода, из-за которого база данных выполняет не тот запрос, что задумал разработчик. В более серьезных случаях так можно не просто обойти фильтр, а вытащить чужие данные (например, через UNION SELECT) или изменить/удалить записи в таблице.
Виды SQL‑инъекций
SQL‑инъекции делят по каналу, через который атакующий получает данные из БД, — это самая распространенная классификация, ее используют OWASP, PortSwigger, Imperva. Существуют три основных вида:
- внутриполосные (in‑band) — код внедряется и результат виден в том же ответе приложения;
- слепые (blind) — прямого ответа нет, вывод делается по косвенным признакам вроде задержки или наличия ошибки;
- внеполосные (out‑of‑band) — данные утекают через сторонний канал, например, DNS-запрос на сервер атакующего.
В примере выше злоумышленник обошел проверку пароля через SELECT‑инъекцию, которую сервер выполнил и сразу вернул результат в ответе, — это классический случай внутриполосной атаки.
Разберем все три вида и приемы внутри них подробнее, а отдельно — еще два признака, по которым инъекции различают независимо от канала: момент срабатывания и формат входных данных.
Внутриполосные (in‑band) инъекции
Определение версии БД или получение скрытых/конфидициальных данных (например, логины и пароли). Самый простой случай: злоумышленник вводит код и получает результат в том же ответе приложения, что и обычный пользователь. Делится на два приема.
- Error‑based. Атакующий намеренно провоцирует ошибку СУБД так, чтобы текст ошибки содержал нужные данные. Например, для MSSQL:
| sql ' AND 1=CONVERT(int, (SELECT @@version))-- |
Попытка привести текстовую версию СУБД к числу вызывает ошибку преобразования (приведения) типов данных, и в сообщении об ошибке приложение случайно выводит саму версию базы.
- UNION‑based. Атакующий добавляет к исходному запросу собственный SELECT через UNION, чтобы вытащить данные из другой таблицы. Пример с товарами интернет‑магазина:
| sql ' AND 1=CONVERT(int, (SELECT @@version))--products WHERE category_id = 1 UNION SELECT username, password FROM users; |
Вместе с товарами на странице отображаются чужие логины и пароли.
Слепые (blind) инъекции
Приложение не показывает ни данные, ни текст ошибки — только «страница загрузилась» или «страница не загрузилась». Атакующий узнает данные по косвенным признакам, задавая базе вопросы «да/нет».
- Boolean‑based. Ответ сервера отличается в зависимости от истинности условия:
| sql 1 AND (SELECT COUNT(*) FROM users WHERE id=5)=1 |
Если страница отобразилась как обычно — условие истинно, пользователь с id=5 существует. Если вернулась ошибка/пустая страница — условие ложно.
- Time‑based. Используется, когда разницы в содержимом ответа нет. Атакующий заставляет СУБД сделать паузу, если условие верно:
| sql ' AND IF(1=1, SLEEP(5), 0)-- |
Ответ приходит с задержкой в 5 секунд — значит, условие истинно. Долго, зато работает даже там, где страница всегда выглядит одинаково.
Внеполосные (out‑of‑band) инъекции
Здесь атакующий не смотрит ни на содержимое ответа, ни на задержку — вместо этого заставляет сервер БД самостоятельно обратиться к внешнему ресурсу, который контролирует атакующий (DNS‑запрос, HTTP‑запрос). Такой подход называют OAST (out‑of‑band application security testing) и применяют, когда ни in‑band, ни blind не дают результата — например, ответ приложения вообще не меняется.
Схема: инъекция заставляет СУБД выполнить сетевой запрос, в который «зашиты» украденные данные (например, как часть DNS‑имени), а атакующий читает их из логов своего DNS‑сервера.
Дополнительные признаки
Два термина, которые часто путают с видами выше, на деле описывают не канал, а другое измерение атаки — и могут сочетаться с любым из трех видов.
По моменту срабатывания
Инъекция первого порядка выполняется сразу при вводе. Инъекция второго порядка сначала сохраняется в БД как обычные данные — например, в поле имени профиля:
| sql John'; DROP TABLE users;-- |
В момент ввода ничего не происходит. Код срабатывает позже, когда это значение используется в другом запросе — например, при формировании отчета администратором.
По формату входных данных
Классическая инъекция — это внедрение в строковый параметр формы или URL, как в примерах выше. Отдельно выделяют JSON/XML‑инъекцию — то же самое, но payload передается через структурированный формат API‑запроса:
| json { "username": "john", "password": "' OR '1' = '1" } |
Если сервер подставляет значение поля в SQL-запрос без проверки, результат тот же — обход проверки пароля.
Как обнаружить SQL-инъекцию
Чтобы обнаружить SQL-инъекцию, важно регулярно анализировать базы данных, а также мониторить сетевой трафик и поведение системы на предмет аномальных признаков:
- Странные параметры в логах, содержащие кавычки, комментарии, ключевые слова SQL: union, select, drop.
- Резкое увеличение объема сетевого трафика к базе данных.
- Подозрительные внешние DNS/HTTP-запросы от сервера баз данных — чаще всего при внеполосных атаках.
- Внеплановое изменение прав пользователей, добавление новых записей, изменение паролей.
- Обнаружение нестандартного или зашифрованного кода в базе данных.
Стоит отметить, что один из перечисленных признаков не всегда указывает на наличие SQL-инъекции, но он точно будет сигналом к дополнительной проверке во избежание возможных атак.
Последствия SQL-инъекций
SQL‑инъекции несут серьезную угрозу для проектов: несанкционированный доступ к базам данных может привести к утечке конфиденциальных данных клиентов, значительным финансовым потерям и подрыву репутации компании. В отдельных случаях результат выходит за рамки экономического ущерба — возможны правовые последствия и уголовная ответственность. Нормативные акты РФ, которые регулируют ответственность за последствия SQL-инъекций:
- Федеральный закон от 27.07.2006 № 152‑ФЗ «О персональных данных» — обязывает операторов принимать меры по защите персональных данных от несанкционированного доступа. Утечка данных через SQL‑инъекцию расценивается как нарушение закона.
- КоАП РФ, статья 13.11 — устанавливает административную ответственность (в том числе крупные штрафы) за нарушение порядка обработки и защиты персональных данных, включая их неправомерную передачу вследствие уязвимостей.
- УК РФ, статья 272.1 — предусматривает уголовную ответственность за незаконное использование, передачу, сбор и хранение персональных данных, полученных через уязвимости (в том числе и SQL‑инъекции).
Как предотвратить SQL-инъекции
В сфере защиты от атак и превентивных мер критически важна регулярность. Все приведенные ниже рекомендации необходимо внедрить и поддерживать на постоянной основе.
- Всегда отслеживайте обновления и устанавливайте актуальные версии серверного ПО, библиотек и CMS.
- Регулярно проверяйте производительность приложений с помощью комплексных инструментов. Например, Apache JMeter, Gatling или SQLMap.
- Используйте WAF, который с помощью соответствующих настроек будет фильтровать вредоносные SQL-запросы.
- Тщательно проверяйте данные, вводимые пользователями, — независимо от того, поступают ли они от авторизованных или внутренних пользователей. Кроме того, учетные записи, имеющие доступ к SQL‑базе данных, следует наделить ограниченными правами, достаточными для выполнения их прямых задач.
- Изучите официальные документы и руководства по борьбе с SQL-инъекциями от OWASP: Annotated Application Security Verification Standard (AASVS), SQL Injection Prevention Cheat Sheet, Query Parameterization Cheat Sheet, OWASP Top 10 и другие. Эти документы содержат комплексную информацию о SQL-инъекциях, их типах, методах обнаружения и предотвращения.




