SQL инъекции и какие есть заблуждения в устранении её

Сегодня хочу затронуть тему SQL-инъекций и особенно остановиться на том, как их правильно устранять.

━━━━━━━━━━ Что такое SQL-инъекция ━━━━━━━━━━

SQL-инъекция — это уязвимость, при которой пользовательские данные попадают в SQL-запрос так, что атакующий может изменить его логику.

Условный пример: • SELECT * FROM users WHERE username = '$username' AND password = '$password';

Если в username передать: • ' OR 1=1; --

то итоговая логика запроса может измениться: • SELECT * FROM users WHERE username = '' OR 1=1; --' AND password = '...'

Здесь OR 1=1 делает условие истинным, а -- комментирует остаток запроса, чтобы не получить синтаксическую ошибку.

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

━━━━━━━━━━ Какие бывают SQLi ━━━━━━━━━━

Если коротко, SQL-инъекции можно разделить на видимые и слепые.

UNION-based SQLi Когда результат запроса возвращается в ответе, мы можем использовать UNION, чтобы добавить к легитимной выборке данные из других таблиц.

Error-based SQLi Когда приложение или БД возвращают ошибки, через них можно вытягивать структуру или данные.

Boolean-based blind SQLi Когда данные не отображаются напрямую, но можно задавать вопросы в стиле “истина / ложь” и по разнице в ответе постепенно восстанавливать данные.

Time-based blind SQLi Похожая история с булевым значением, но вместо разницы в содержимом используется задержка, например через sleep.

Out-of-band SQLi Когда результат уходит не в HTTP-ответ, а через внешний канал, например DNS/HTTP-запрос от БД на контролируемый сервер.

━━━━━━━━━━ Где изучать глубже ━━━━━━━━━━

Во все времена и все советуют ресурс — PortSwigger Web Security Academy.

Там можно не просто прочитать про SQLi, но и порешать лабы: ➥ https://portswigger.net/web-security/sql-injection

━━━━━━━━━━ Главное заблуждение при фиксе ━━━━━━━━━━

Много где пишут: “используйте параметризованные запросы”. И это от части правильный совет.

Но важно понимать нюанс: ➤ параметры защищают значения, но не защищают структуру SQL-запроса.

То есть вот так — хорошо: • WHERE username = ?

А вот так — уже плохо: • ORDER BY + userInput • SELECT * FROM + tableName • WHERE + rawCondition

Проблема появляется там, где пользовательский ввод снова начинает влиять на саму структуру SQL.

━━━━━━━━━━ Где параметризация ломается ━━━━━━━━━━

Динамический ORDER BY Плохая идея: • ORDER BY + sort Если пользователь может передать sort, он влияет на структуру запроса.

Динамическое имя таблицы или колонки Плохо: • SELECT * FROM + tableName Параметры обычно не предназначены для подстановки имён таблиц и колонок.

Часть WHERE собирается строкой Плохо: • WHERE status = ? AND + filter Даже если часть запроса параметризована, небезопасный кусок строки может вернуть SQLi обратно.

Stored Procedures не всегда безопасны Stored procedure сама по себе не гарантирует защиту. Если внутри процедуры есть dynamic SQL и склейка строк, проблема остаётся: • EXEC('SELECT * FROM users WHERE name = ''' + @name + '''')

ORM тоже не панацея ORM безопасен, пока используется его нормальные методы. Но как только начинается: • raw() • createQuery() • query("SELECT ... " + userInput) то мы вновь собираем SQL запрос и можем получить ту же самую SQL-инъекцию.

━━━━━━━━━━ Как защищаться нормально ━━━━━━━━━━

Минимальный набор: • параметризованные запросы для значений • никакой склейки пользовательского ввода с SQL • белые списки ввода пользователя • осторожность с raw SQL и stored procedures • минимум прав у пользователя БД • тесты на инъекции в критичных ручках

#AppSec #SQLi #SQLInjection #Pentest #CyberSecurity #OWASP #Portswigger #IT

SQL инъекции и какие есть заблуждения в устранении её | Сетка — социальная сеть от hh.ru