7. Защита: типизация и валидация ввода
Эшелонированная оборона: Валидация и Типизация
Prepared Statements — это база, но настоящая безопасность строится на принципе эшелонированной обороны. Мы можем добавить дополнительные проверки на уровне кода, которые остановят атаку еще до обращения к базе данных.
Концепция Defense in Depth родилась в военном деле — крепости строили с несколькими линиями стен, и пробитие одной не означало взятия города. В компьютерной безопасности этот принцип формализован в NIST Cybersecurity Framework: ни одна защитная мера не может быть единственной точкой отказа. Если атакующий пробивает одну линию, его должна остановить следующая, потом ещё одна, потом ещё. Для SQL-инъекций это означает: валидация типа на входе → whitelist regex → параметризованные запросы → least-privilege database user → network policy. Атакующему нужно пробить все слои сразу, что превращает 5-минутную атаку через sqlmap в многонедельный проект, требующий ресурсов APT-группы.
Аналогия: представь банковское хранилище. Сначала охранник на ресепшен проверяет пропуск (типизация); потом сотрудник лично сопровождает посетителя (валидация); затем биометрия на входе в хранилище (Prepared Statements); далее каждая ячейка открывается только при сочетании ключа клиента и мастер-ключа банка (least privilege); камеры наблюдения фиксируют всех (мониторинг). Грабитель, преодолевший один слой, упирается в следующий. Чем больше слоёв — тем выше стоимость атаки и больше шансов её детектировать.
Посмотрим, как типизация данных и валидация ввода создают второй рубеж защиты, делая работу хакера еще сложнее.
1. Типизация как первичная защита
Представьте, что вы принимаете id из URL: https://myapp.com/user?id=123.
Хакер пробует: id=123 OR 1=1.
Это самый простой и одновременно самый эффективный фильтр для числовых параметров. Если поле по бизнес-логике может содержать только целое число (id записи, страница пагинации, лимит выборки), нет ни одной причины принимать строку. strconv.Atoi возвращает ошибку для любого ввода, не являющегося валидным числом — и эта ошибка останавливает обработку запроса задолго до того, как payload достигнет SQL.
Если ваш Go-код пытается превратить этот id в число:
// ✅ ПРАВИЛЬНЫЙ Go-код (Типизация)
idStr := r.URL.Query().Get("id")
id, err := strconv.Atoi(idStr)
if err != nil {
// Хакер "отсекается" уже здесь!
http.Error(w, "Invalid ID format", http.StatusBadRequest)
return
}
// В базу летит ЧИСТОЕ число id
db.Query("SELECT * FROM users WHERE id = ?", id)
В этом примере хакерское выражение ' OR 1=1 упадет на этапе strconv.Atoi, так как это не целое число. Атака даже не дойдет до SQL!
Дополнительные проверки целочисленного типа: после Atoi имеет смысл проверить, что значение в допустимом диапазоне (if id < 1 || id > maxValidID). Иначе атакующий может передать огромное число 999999999999 и получить error при обращении к несуществующей записи — что в худшем случае выдаст stack trace с именами таблиц через 500 Internal Server Error. Range validation закрывает этот вектор.
2. Валидация через регулярные выражения (Regexp)
Если вы принимаете строку (например, имя пользователя или SKU товара), которая должна иметь определенный формат, используйте regexp. Это «whitelist» подход в чистом виде — мы явно описываем, какие символы допустимы, и всё остальное отвергаем без обсуждения.
// Допустимы только буквы и цифры, от 3 до 20 символов
re := regexp.MustCompile("^[a-zA-Z0-9]{3,20}$")
if !re.MatchString(username) {
http.Error(w, "Invalid username", http.StatusBadRequest)
return
}
3. Таблица "Defense in Depth" (Эшелонированная оборона)
| Слой защиты | Что делает? | Пример на Go |
|---|---|---|
| 1. Типизация | Проверяет тип данных | strconv.Atoi(id) |
| 2. Валидация | Проверяет формат | regexp.MustCompile(...) |
| 3. Prepared Statements | Разделяет код и данные | db.Query(..., id) |
| 4. Least Privilege | Ограничивает права в БД | GRANT SELECT ON ... |
4. Почему "Черные списки" (Blacklist) — это зло?
Никогда не пытайтесь "запрещать" слова SELECT, OR, UNION или кавычки. Хакеры найдут тысячи способов их обойти: кодировки, регистр, пробелы.
Золотое правило Go-разработки:
Используйте Белые списки (Allowlist) — разрешайте только то, что вы ОЖИДАЕТЕ (например, только цифры для ID).
Принцип «fail-safe defaults» из работы Зальцера-Шредера 1975 года остаётся актуальным: по умолчанию запрещено всё, явно разрешено только нужное. Allowlist-подход даёт гарантию: даже если в будущем кто-то изобретёт новую обфускацию, ваш фильтр всё равно её отвергнет — потому что новый payload точно не входит в список разрешённых паттернов. Blacklist-подход требует обновлений каждый раз, когда исследователи находят новый bypass; allowlist — нет.
Чем больше слоев защиты, тем меньше шансов у злоумышленника. Валидация на уровне Go — это отличный способ отсечь 90% попыток взлома еще на входе.
Соответствие стандартам: OWASP ASVS v4 раздел 5 «Validation, Sanitization and Encoding» формализует требования к input validation; OWASP Cheat Sheet «Input Validation Cheat Sheet» даёт практические рекомендации; CWE-20 «Improper Input Validation» — отдельная категория CVE для невалидированных входов; NIST SP 800-53 SI-10 «Information Input Validation». Аудиторы PCI ожидают увидеть документированные правила валидации для каждого API endpoint, обрабатывающего данные карточек.
Вы изучили основы инъекций и узнали, как от них защититься. Впереди — проверка знаний в квизе и первая серьезная лабораторная работа.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.