5. Уязвимости ORDER BY / GROUP BY (без Prepared)
Уязвимости ORDER BY: Где Prepared Statements бессильны
Динамическая сортировка (ORDER BY) — одна из самых коварных ловушек для Go-разработчика. Мы усвоили, что Prepared Statements защищают нас везде, где передаются данные (например, WHERE id = ?). Однако в SQL есть структурные элементы, которые нельзя параметризовать стандартным способом — это имена таблиц, колонок и направления сортировки.
Разберем, как возникают уязвимые API-интерфейсы и как злоумышленники используют «сортировку» для кражи данных.
1. Механика: "Ловушка ORDER BY"
Представьте типичный код для получения списка товаров с сортировкой:
sortBy := c.Query("sort") (пользователь передает name или price).
query := fmt.Sprintf("SELECT id, name FROM products ORDER BY %s", sortBy)
Хакеру не интересна очередность товаров. Он внедряет логическое условие:
?sort=1 AND (SELECT ASCII(SUBSTRING(password, 1, 1)) FROM users LIMIT 1) = 65
Что происходит: Если условие истинно (первая буква пароля — 'A'), база отсортирует результат по первой колонке. Если ложно — сортировка будет иной. Анализируя порядок элементов на странице, хакер постепенно восстанавливает секретные данные.
2. Почему обычные плейсхолдеры здесь не работают
Если вы попытаетесь использовать защиту «в лоб»: db.Query("... ORDER BY ?", sortBy), драйвер Go подставит значение как строку в кавычках.
- Вы ожидали:
ORDER BY price - База получила:
ORDER BY 'price'
Для SQL-сервера ORDER BY 'price' — это сортировка по константе, то есть отсутствие какой-либо осмысленной сортировки. Именно поэтому разработчики часто возвращаются к небезопасной конкатенации, совершая фатальную ошибку.
3. Безопасность vs Уязвимость
| Подход | Код (Пример) | Оценка безопасности |
|---|---|---|
| Опасный | ORDER BY %s (прямая вставка) |
🔴 SQL Injection |
| Надежный | Сверка со списком (Whitelist) | 🟢 Полная защита |
4. Единственное верное решение: White-listing
Если вам нужна динамическая сортировка в Go, никогда не передавайте ввод пользователя напрямую в SQL. Единственный безопасный путь — проверить, входит ли полученная строка в заранее определенный список разрешенных колонок:
// ✅ БЕЗОПАСНО: Проверка по белому списку
allowed := map[string]bool{"name": true, "price": true}
if !allowed[sortBy] {
sortBy = "id" // Значение по умолчанию
}
query := fmt.Sprintf("... ORDER BY %s", sortBy) // Теперь это безопасно
5. Сравнение подходов защиты ORDER BY
| Критерий | Fix A: Whitelist + database/sql |
Fix B: squirrel / ORM |
|---|---|---|
| Метод | map[string]bool + fmt.Sprintf (только проверенные значения) |
sq.OrderBy() / db.Order() с whitelist |
| Зависимости | Нет — только stdlib | squirrel или GORM |
| Преимущество | Простота, нет внешних зависимостей | Fluent API, сложные сортировки без конкатенации |
| Важно | Whitelist обязателен в обоих подходах — ни один query builder не валидирует имена колонок автоматически |
Динамический SQL — это всегда риск. Хакеру достаточно внедрить одно условное выражение в блок сортировки, чтобы превратить ваш интерфейс в инструмент для посимвольного перебора паролей.
Мы завершили изучение методов обхода фильтров. После квиза нас ждет финальный раздел — знакомство с инструментами автоматизации SQL-инъекций.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.