6. Почему fmt.Sprintf убивает безопасность
Почему fmt.Sprintf убивает безопасность в Go
Введение
Что общего у новичка в Go и уязвимого приложения? Оба обожают fmt.Sprintf. Это мощный, красивый инструмент форматирования строк. Но когда речь заходит о базах данных, fmt.Sprintf — это билет в один конец до взлома.
В этом подмодуле мы изучим Го-специфику: почему пересылка строки query через db.Query — это не безопасность, а имитация.
1. fmt.Sprintf vs db.Query(query, args)
В Go есть два способа сформировать и отправить запрос в базу данных. Один смертелен, второй — безопасен.
Вариант ❌: Смертельная конкатенация
// Хакер "вклеивается" в вашу строку на этапе Sprintf
query := fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", username)
db.Query(query) // База получает ГОТОВУЮ строку 'SELECT... vasya OR 1=1'
В этом варианте Go просто подставил одну строку в другую. База данных видит цельную команду и ПАРСИТ её (выполняет).
Вариант ✅: Параметризованный запрос (Prepared)
// Мы разделяем КОД и ДАННЫЕ
query := "SELECT * FROM users WHERE name = ?"
db.Query(query, username) // Go отправляет в базу КОД и ДАННЫЕ РАЗДЕЛЬНО
2. Секрет на уровне протокола БД
В чем магия второго варианта?
Когда вы используете db.Query(query, username), Go под капотом говорит базе:
- Шаблон: "Вот мой шаблон запроса:
SELECT * FROM users WHERE name = ?. Подготовься к нему!" - Данные: "А вот данные для этого шаблона: имя
vasya. Просто подставь его и не вздумай выполнять его как код!"
Даже если в имени vasya будет вредоносный код ' OR '1'='1, база данных будет искать пользователя с ТАКИМ длинным и странным именем. Она не будет выполнять OR '1'='1'!
Таблица работы: Код vs Данные
| Тип запроса | Передача в БД | Результат атаки |
|---|---|---|
| Sprintf | Одной строкой | ВЗЛОМ (база выполнит пэйлоад хакера) |
| Prepared | Код + Данные раздельно | БЕЗОПАСНО (база ищет юзера по имени) |
3. Особенности разных баз данных (Placeholder)
В Go плейсхолдеры (?) могут различаться в зависимости от драйвера:
- MySQL/SQLite:
SELECT ... WHERE id = ? - PostgreSQL:
SELECT ... WHERE id = $1 - Oracle:
SELECT ... WHERE id = :name
Но суть остается прежней: данные никогда не должны попадать в строку SQL через форматирование текста в самом Go.
Вывод
fmt.Sprintf — прекрасный инструмент для логов, но худший для SQL-запросов. Если вы видите fmt.Sprintf в коде работы с БД — бейте тревогу. В следующем модуле мы закрепим основы в квизе по вводной части, перед тем как перейти к реальной практике.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.