EMZETT.
Войти

SQLi (SQL-инъекция)

Коротко: Техника атаки, при которой злоумышленники внедряют собственный SQL-код в запрос к базе данных через незащищённые поля ввода — может читать, изменять или удалять данные.

Подробнее: Возникает, когда ввод пользователя подставляется прямо в SQL-запрос без проверки (конкатенация строк вместо параметризованных запросов). Классический пример: в поле входа вводят ' OR '1'='1, и это может обойти проверку пароля. Стандартная защита — параметризованные запросы/подготовленные выражения, при которых ввод пользователя никогда не интерпретируется как исполняемый SQL-код.

Подробности

Уязвимый запрос входа может наивно выглядеть так (конкатенация строк, ввод пользователя вставлен напрямую):

-- Уязвимый код (НИКОГДА так не пишите):
query = "SELECT * FROM users WHERE username = '" + input + "' AND password = '" + pw + "'"
 
-- Ввод: username = admin' --
-- Получившийся запрос:
SELECT * FROM users WHERE username = 'admin' --' AND password = '...'
-- Проверка пароля просто закомментирована с помощью "--" (SQL-комментарий)!

Такими манипуляциями злоумышленник может не только обойти проверку входа, но в зависимости от прав подключения к базе данных также читать целые таблицы (UNION SELECT для подмешивания данных из других таблиц в вывод), изменять или удалять данные, а в худших случаях даже выполнять команды на самом сервере базы данных.

Надёжная защита структурная, а не «отфильтровывание опасных символов»:

// Безопасно: параметризованный запрос - ввод НИКОГДА не интерпретируется как SQL-код
db.query("SELECT * FROM users WHERE username = $1", [input])

При параметризованных запросах (также «prepared statements») приложение отправляет базе данных структуру запроса и ввод пользователя раздельно — благодаря этому база данных всегда знает, какая часть «код» (структура запроса), а какая — чистые «данные» (ввод), что бы пользователь ни вводил. Современные ORM (см. Drizzle ORM) по умолчанию используют внутри параметризованные запросы, поэтому при правильном применении ORM SQL-инъекция практически исключена — сырой SQL с конкатенацией строк остаётся возможным и опасным в любом языке/фреймворке.

Слепая SQL-инъекция

Уязвимое приложение не всегда прямо выводит ошибки базы данных или результаты запросов — при «слепой SQL-инъекции» атакующий не видит прямой обратной связи, но всё же может извлекать информацию, формулируя условия, заметно влияющие на поведение приложения (например, другое время ответа или другая страница в зависимости от того, истинно ли условие). Пример: ' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a — если приложение отвечает так же, как без условия, догадка верна, иначе нет. Символ за символом таким способом теоретически можно извлечь полный пароль, даже без видимых сообщений об ошибках — значительно медленнее классической SQLi, но не менее опасно.

Дополнительные уровни защиты

Параметризованные запросы — важнейшая, но не единственная линия защиты. Принцип наименьших привилегий ограничивает ущерб даже от успешной инъекции: пользователь базы данных, под которым подключается веб-приложение, должен иметь только действительно нужные права (например, не иметь права DROP TABLE для чисто читающего эндпоинта). Межсетевой экран веб-приложений (WAF) дополнительно может распознавать и блокировать известные шаблоны инъекций во входящем трафике ещё до того, как они достигнут приложения — как дополнительная страховка, а не замена безопасного доступа к базе данных в самом коде. Регулярные автоматические сканирования безопасности (например, инструментами вроде sqlmap в рамках собственных тестов) помогают рано находить случайно внесённые дыры инъекций, прежде чем это сделает реальная атака.

См. также: SQL, Поддельные cookie