Перейти к содержимому
Назад к пути
Теория 3 мин чтения

4. Защита: таймауты в Go (context)

Защита: Таймауты в Go (context)

Механизм context.Context в Go — это фундаментальный инструмент для управления жизненным циклом операций. В контексте безопасности таймаут (Timeout) на уровне вашего кода становится критически важным барьером для Time-based инъекций. Это яркий пример стратегии эшелонированной обороны (Defense in Depth), где вы защищаете ресурсы, даже если первичная защита была пробита.

Разберем, как QueryContext спасает ваш пул соединений от «заснувших» атак.


1. Механика: "Время вышло!"

Без ограничений по времени хакер может заставить базу данных «спать» сколько угодно, парализуя работу сервера. Правильный подход в Go — всегда задавать жесткие границы исполнения.

// ✅ ПРАВИЛЬНЫЙ Go-код (Context Timeout)
// Устанавливаем лимит на запрос к БД — например, 3 секунды
ctx, cancel := context.WithTimeout(r.Context(), 3*time.Second)
defer cancel()

// Используем QueryContext вместо обычного Query
rows, err := db.QueryContext(ctx, "SELECT id FROM items WHERE id=$1", id)
if err != nil {
    if err == context.DeadlineExceeded {
        // Запрос принудительно прерван через 3 секунды
        log.Println("Предупреждение: Таймаут запроса к БД")
    }
}

Даже если хакер успешно внедрит pg_sleep(10), пакет database/sql разорвет соединение ровно через 3 секунды.


2. Как это ломает Time-based SQLi?

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

Но важнее всего защита ресурсов: вы не позволяете хакеру забить пул соединений. Зависшие запросы будут отсекаться быстро, освобождая место для реальных пользователей. Сайт продолжит работать даже под массированной атакой.


3. Настройка пула соединений

Никогда не оставляйте конфигурацию sql.DB по умолчанию в боевых условиях:

Параметр Рекомендация Назначение
SetMaxOpenConns 50-100 Ограничение емкости пула
SetConnMaxLifetime 5-10 мин Ротация старых соединений
QueryContext Всегда Противодействие зависаниям

4. Сигналы в логах

Регулярное появление ошибок context deadline exceeded — это серьезный повод для аудита. Это может означать как проблемы с производительностью базы, так и то, что злоумышленники пытаются применить технику Time-based SQLi к вашим эндпоинтам.


5. Эшелон 2: Allowlist-валидация входных данных + параметризация

Параметризация — основная защита, но для значений со строгим форматом (UUID, числовые ID, slug) полезен второй слой: regex-allowlist, который отсекает всё нестандартное до обращения к БД. Это особенно важно для HTTP-заголовков и cookie, где ввод не контролируется HTML-формой.

// Компилируется один раз при старте приложения
var headerPattern = regexp.MustCompile(`^[a-fA-F0-9\-]{1,64}$`)

func handler(w http.ResponseWriter, r *http.Request) {
    headerValue := r.Header.Get("X-Custom-ID")
    if headerValue == "" {
        return
    }

    // Уровень 1: allowlist — отсекаем всё, что не похоже на UUID
    if !headerPattern.MatchString(headerValue) {
        log.Printf("rejected invalid header value from %s", r.RemoteAddr)
        return
    }

    // Уровень 2: параметризация — даже при обходе regex SQL-инъекция невозможна
    db.Exec("INSERT INTO logs (key, ua) VALUES (?, ?)", headerValue, "Go")
}

Почему два уровня лучше одного:

  • Allowlist (уровень 1) блокирует payload в формате ' || (CASE WHEN ...) || ' ещё до запроса к БД и оставляет след в логах.
  • Параметризация (уровень 2) страхует от ошибок в regex (например, при будущем расширении формата tracking_id).

Если уровень 1 будет случайно ослаблен — уровень 2 продолжит надёжно защищать. Это и есть defense-in-depth: безопасность не зависит от единственного механизма.

Сравнительная таблица для time-based защиты:

Подход Уровни Блокировка до БД Логирование атак Когда применять
Только параметризация 1 (БД) Нет Нет Доверенные внутренние API
Только allowlist 1 (приложение) Да Да НЕ ДОСТАТОЧНО — обход regex = SQLi
Allowlist + параметризация 2 Да Да Публичные API, заголовки, куки

Если нужно выбрать одно — выбирайте параметризацию. Allowlist без параметризации — это снова разновидность blacklist'а, его можно обойти; параметризация без allowlist лишает приложение быстрого rejection-логирования и тратит ресурсы БД на заведомо невалидный ввод.


Таймауты в Go — это ваш последний рубеж. Они не заменяют параметризацию запросов, но делают систему устойчивой к попыткам парализовать её работу и лишают хакера возможности «тихой» разведки.

Мы завершили изучение временных инъекций. После квиза вас ждет закрепление материала на практике, а затем мы перейдем к одной из самых хитрых тем — инъекциям второго порядка.

Продолжить чтение

Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу

Когда закончишь — отметь раздел, чтобы продолжить.

🚧 Сайт в разработке. Полный функционал пока недоступен. Все вопросы — support@hackandfix.ru