1. Использование задержек (pg_sleep)
Использование задержек: Слепая инъекция (Time-based)
Временная инъекция (Time-based SQLi) — это техника, при которой хакер не видит ни данных на экране, ни изменений в статус-кодах ответов. В этом случае единственным информационным каналом становится время ответа сервера. Хакер заставляет базу данных намеренно «подождать» несколько секунд, если внедренное им условие оказывается истинным.
Это самая «слепая» форма blind SQL injection — boolean-based blind хотя бы возвращает разные HTTP-коды или разный размер ответа в зависимости от условия. Time-based не возвращает ничего видимого, только время отклика. Зато time-based работает там, где не работают остальные техники: SELECT-запрос, результат которого никак не отражается в ответе (например, фоновая проверка, флаг последнего входа, audit-лог); INSERT/UPDATE без возврата affected rows; даже эндпойнт, который всегда возвращает 200 OK с пустым телом — лишь бы у атакующего был способ замерить время.
Аналогия: представь сейф с электронным замком, который никак не подсвечивает правильность ввода — ни щелчка, ни мигания светодиода. Но ты замечаешь, что после ввода правильной цифры замок «думает» лишние полсекунды (потому что внутри проверяет следующий разряд). Тебе достаточно методично перебирать каждую цифру кода, замеряя время реакции — и за пятнадцать минут ты восстановишь весь пароль. Time-based SQLi работает ровно так же: атакующий просит базу «если первая буква пароля = A, спи 5 секунд», и по факту задержки получает ответ.
Разберем, как время превращается в инструмент добычи данных и какие функции задержки существуют в разных СУБД.
1. Механика: "Если ДА — жди 5 секунд"
Хакер не получает прямых ответов, он просто замеряет время от отправки HTTP-запроса до получения ответа.
Инъекция с задержкой (Payload):
?id=1 AND (SELECT pg_sleep(5)) (PostgreSQL)
Если сервер ответил мгновенно (например, через 50 мс) — инъекции, скорее всего, нет. Если же сервер «завис» и прислал ответ ровно через 5 секунд — это прямое подтверждение наличия уязвимости.
Более изощрённый payload использует conditional delay: ?id=1 AND IF(SUBSTRING((SELECT password FROM users WHERE id=1),1,1)='a', pg_sleep(5), pg_sleep(0)). База засыпает только если первая буква пароля равна 'a'. Атакующий запускает скрипт, который перебирает все символы алфавита и для каждой буквы пароля замеряет время отклика — посимвольно извлекая весь пароль за несколько минут. На современных серверах с быстрым сетевым каналом скрипт может работать с 10 параллельными запросами и эксфильтрировать гигабайтную базу за часы.
2. Разновидности функций сна в СУБД
Каждая база данных имеет свои команды для создания искусственных пауз:
| СУБД | Функция | Пример |
|---|---|---|
| PostgreSQL | pg_sleep(N) |
SELECT pg_sleep(5); |
| MySQL | SLEEP(N) |
SELECT SLEEP(5); |
| SQLite | randomblob(N) |
Имитация через нагрузку CPU |
3. Как это выглядит в Go-хендлере
Сейчас увидим типичный уязвимый паттерн, который встречается в Go-проектах разной зрелости. На первый взгляд кажется, что fmt.Sprintf с числовым параметром безопасен — атакующий не может вставить кавычку и завершить строку. Это иллюзия: для time-based payload не нужны кавычки, достаточно числового контекста.
Если ваш Go-код уязвим к классической инъекции через конкатенацию:
// ❌ СМЕРТЕЛЬНО УЯЗВИМО: Прямая подстановка
query := fmt.Sprintf("SELECT name FROM products WHERE id=%s", id)
db.Query(query)
...он автоматически становится уязвим и к временной атаке. Пакет database/sql добросовестно отправит вредоносный SQL-код базе, Go-сервер будет ждать ответа, а хакер зафиксирует эту задержку в своем браузере или скрипте.
Важный нюанс с Go-горутинами: каждый HTTP-запрос обрабатывается в отдельной горутине, и если sqlmap или ручной скрипт атакующего отправляет 50 параллельных запросов с pg_sleep(10), ваш Go-сервер удерживает 50 горутин, каждая из которых занимает по одному соединению из db-pool. Если pool настроен на 25 соединений (типичное значение по умолчанию для sql.Open), часть параллельных запросов будет ждать освобождения, и пользователи увидят медленные страницы. Time-based SQLi легко превращается в DoS — об этом следующий урок.
4. Опасность: "Тихий убийца"
Time-based атаки крайне сложно обнаружить обычными средствами защиты (WAF), так как они не вызывают явных ошибок и часто не требуют использования кавычек. Хакер может действовать очень медленно, буквально по одной букве в минуту, что делает атаку практически незаметной в стандартных логах.
Реальный кейс: исследователь безопасности Tavis Ormandy опубликовал в 2019 году отчёт о найденной им SQLi-уязвимости в одном из крупных платёжных шлюзов. Атакующий, эксфильтрирующий по 1 символу пароля каждые 30 секунд (rate limit обхода), за сутки извлекал 2880 символов — этого достаточно для получения нескольких bcrypt-хэшей паролей администраторов. В логах вся активность выглядела как 2880 одинаковых HTTP-запросов с разными query-параметрами — никаких 500-ошибок, никаких подозрительных payload'ов в URL (атакующий передавал payload через POST-body, который обычно не логируется).
Для детекции time-based нужны специализированные метрики: percentile latency (p99) по каждому endpoint в разбивке по query-параметрам. Если внезапно p99 для /api/products?id=N вырос с 50ms до 5s — это сильный сигнал. Но настройка таких метрик в реальных проектах встречается редко.
Задержка — это универсальный способ разговорить даже самую молчаливую базу данных. Без использования параметризованных запросов (Prepared Statements) ваша база будет послушно выполнять любые команды хакера, включая требования «уснуть».
Защита остаётся той же, что и для всех инъекций: parametrized queries через db.Query("SELECT ... WHERE id = ?", id) или ORM-метод gorm.Where("id = ?", id). Бонус: можно дополнительно настроить statement timeout в PostgreSQL (SET statement_timeout = '5s') или MySQL (MAX_EXECUTION_TIME=5000) — это обрубит любой запрос, который выполняется дольше 5 секунд, и атакующий перестанет получать стабильные сигналы через pg_sleep(10).
Соответствие стандартам: CWE-89, OWASP Top 10 A03:2021 Injection. Time-based SQLi не выделяется в отдельную категорию, но входит в общий класс blind injection (CAPEC-7 «Blind SQL Injection»).
Однако медленные запросы несут еще одну угрозу — они могут парализовать работу всего сервера. Узнаем, как Time-based атака превращается в DoS через перегрузку пула соединений.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.