3. Условные операторы и задержки
Условные операторы и задержки: "Если — То — Засни"
Time-based инъекция — это фактически «двоичный код времени». Хакеру недостаточно просто остановить работу базы; ему нужно, чтобы она замирала только при выполнении определенного условия (например, если первая буква пароля администратора — 'A'). Так он получает подтверждение своих догадок через паузы в ответах.
Разберем, как с помощью SQL-операторов CASE или IF злоумышленник управляет временем ответа вашего Go-приложения.
1. Механика: "Если — То — Сон"
Хакер внедряет логическую конструкцию прямо в запрос. Вот как это выглядит на практике:
Пример для PostgreSQL:
1 AND (SELECT CASE WHEN (1=1) THEN pg_sleep(5) ELSE pg_sleep(0) END)
- Если условие
1=1(Истина) — база выполняет командуpg_sleep(5). Ответ задержится на 5 секунд. - Если условие
1=2(Ложь) — выполняетсяpg_sleep(0). Сервер отвечает мгновенно.
2. Разница синтаксиса в СУБД
Хакеры адаптируют атаку под конкретный движок базы данных:
| СУБД | Синтаксис условия | Пример атак |
|---|---|---|
| PostgreSQL | CASE WHEN (cond) THEN pg_sleep(5) ELSE pg_sleep(0) END |
... WHEN (SUBSTR(pass,1,1)='A') THEN... |
| MySQL | IF(cond, SLEEP(5), 0) |
... IF(1=1, SLEEP(5), 0) |
| SQLite | Сложная логика через нагрузку CPU | ... CASE WHEN (1=1) THEN r_blob(10) ELSE 0 END |
3. Финальный удар: Извлечение данных
Хакер отправляет запрос, который по одному символу проверяет ваш секретный токен:
?id=1 AND (SELECT CASE WHEN (SUBSTRING((SELECT token FROM config LIMIT 1), 1, 1) = 'a') THEN pg_sleep(5) ELSE pg_sleep(0) END)
Если ответ пришел с задержкой в 5 секунд — хакер точно знает, что первая буква секретного значения — это 'a'.
4. Почему Go позволяет это делать?
Проблема в том, что когда разработчик использует fmt.Sprintf или конкатенацию для сборки запроса, вредоносный SQL-код беспрепятственно попадает в базу. Драйвер Go считает это обычной командой и честно ждет её завершения. Всё, что видит приложение — это долгий ответ от СУБД.
5. Точка входа — не только URL и тело запроса
Многие забывают, что HTTP-заголовки — такой же источник пользовательского ввода, как параметры формы. Если backend читает значение заголовка (например, кастомного для аналитики или User-Agent для логов) и подставляет его в SQL через конкатенацию, то заголовок становится точкой инъекции. Это особенно коварно для INSERT-запросов: ответ возвращает 200 OK независимо от данных, и единственный наблюдаемый сигнал — время отклика.
Шаблон INSERT-инъекции через конкатенацию
Уязвимый код приложения часто формирует INSERT через fmt.Sprintf:
// ❌ УЯЗВИМО: значение заголовка вклеивается в строку SQL
query := fmt.Sprintf("INSERT INTO logs (key, ua) VALUES ('%s', 'Go')", header)
db.Exec(query)
Чтобы проверить уязвимость и одновременно встроить условную задержку, payload должен «зашить» оператор конкатенации SQL в значение поля. В SQLite оператор склейки строк — ||:
' || (CASE WHEN (1=1) THEN (SELECT count(hex(randomblob(200000000)))) ELSE 0 END) || '
Структура шаблона:
'— закрывает текущий строковый литерал вVALUES ('...').||— оператор конкатенации SQLite (в MySQL это будетCONCAT(...), в PostgreSQL тоже||).(CASE WHEN <предикат> THEN <heavy_query> ELSE 0 END)— условная задержка: при истине считаем тяжёлыйrandomblob, иначе мгновенный0.|| '— снова склейка с пустой строкой, чтобы исходный INSERT остался синтаксически корректным.
После подстановки шаблон превращается в:
INSERT INTO logs (key, ua) VALUES ('' || (CASE WHEN (1=1) THEN (...) ELSE 0 END) || '', 'Go')
Запрос валиден, ответ всё равно возвращает 200 OK, но при истинности предиката база уйдёт на ~2 секунды считать randomblob. Ровно эта задержка — единственный observable сигнал для INSERT-инъекции, где данные не возвращаются клиенту.
Лабораторная этого модуля строится именно на таком сценарии. Точка входа — обычная страница каталога, без формы и без видимого поля для ввода: payload уходит в HTTP-заголовок запроса, и единственный сигнал для атакующего — задержка ответа сервера:

Чтобы построить условную задержку, в значении заголовка нужно: закрыть строковый литерал, через оператор конкатенации (|| в SQLite) встроить CASE WHEN ... THEN heavy_query ELSE 0 END и снова открыть кавычку, чтобы исходный INSERT остался синтаксически валидным. Конкретные пейлоады в подсказках лабы намеренно не приведены — собрать их студент должен сам, опираясь на разобранную выше теорию CASE WHEN и оракул TRUE = медленный ответ.
Условные задержки превращают базу в «молчаливого свидетеля», который выдает секреты через паузы в разговоре. Это делает атаку крайне незаметной для стандартных систем мониторинга производительности.
Однако у Go есть мощный механизм контроля ресурсов, который может стать серьезной преградой для таких атак. Узнаем, как использование контекстов и таймаутов спасает приложение.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.