4. Фундаментальная защита: Prepared Statements
Prepared Statements: Серебряная пуля
Если бы существовала «серебряная пуля» в безопасности баз данных, это были бы подготовленные выражения. Они решают проблему SQL-инъекций в самом корне, проводя непробиваемую границу между кодом программы и данными пользователя.
Разберемся, почему этот подход делает инъекцию физически невозможной и как это работает под капотом.
1. Как это работает: Разделение КОДА и ДАННЫХ
В уязвимом коде вы смешиваете команду (SELECT) и данные (id=123) в одну строку в самом Go. База данных получает эту строку и пытается её РАСПОЗНАТЬ (PARSING).
В Prepared Statements сценарий меняется:
- PREPARE: Go говорит базе: "Вот мой шаблон запроса:
SELECT * FROM users WHERE id = ?. Подготовься к нему!" (База парсит шаблон БЕЗ данных). - BIND: Go говорит базе: "А вот данные для этого шаблона:
123. Просто подставь их в готовый шаблон и не пытайся их выполнять как код!". - EXECUTE: База выполняет уже готовый запрос с подставленными данными.
2. Почему это на 100% безопасно?
Даже если хакер подставит в ? вредоносный код типа 1' OR '1'='1, для базы данных это будет просто ДЛИННАЯ СТРОКА ТЕКСТА. Она никогда не попадет в этап парсинга (Parsing stage). База будет искать пользователя с ТАКИМ странным именем 1' OR '1'='1. Соответственно, хакер ничего не добьется.
Таблица работы: Sprintf vs Prepared
| Параметр | Использование Sprintf | Использование Prepared |
|---|---|---|
| Процесс | Парсим всю строку целиком | Парсим шаблон, BINDим данные |
| Безопасность | 🔴 УЯЗВИМО | 🟢 АБСОЛЮТНО БЕЗОПАСНО |
| Скорость | 🌕 Обычная | 🌕 Высокая (шаблон повторен) |
| Вердикт | Смерть через взлом | ЗОЛОТОЙ СТАНДАРТ |
3. Как это выглядит в Go (библиотека database/sql)
// ✅ ПРАВИЛЬНЫЙ Go-код (Prepared Statements)
query := "SELECT id FROM users WHERE username = ? AND password = ?"
err := db.QueryRow(query, username, password).Scan(&userID)
В этом примере Go-пакет database/sql сам берет на себя всю работу по отправке шаблона и данных в базу раздельно.
4. Сравнение подходов: stdlib vs библиотека
| Критерий | Fix A: database/sql (stdlib) |
Fix B: sqlx / squirrel / GORM |
|---|---|---|
| Зависимости | Нет — только стандартная библиотека | Внешний пакет (go get ...) |
| Параметризация | Ручная (? / $1) |
Автоматическая (fluent API или struct mapping) |
| Преимущество | Минимум зависимостей, полный контроль | Читаемость, защита от ошибок при сложных запросах |
| Риск | Легко забыть ? в одном месте |
Raw-запросы внутри ORM остаются уязвимыми |
Разделение контекста — это закон. Когда данные не могут стать кодом, хакер теряет свою силу.
Теперь посмотрим, как реализовать этот принцип в Go, используя стандартную библиотеку database/sql.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.