> Может ли в SQL-запросе быть инъекция и как ее предотвратить (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Т-Банк
Стек: Go
> Пример ответа
Короткий ответ
Да, SQL-инъекция возможна в любом языке, включая Go, если запрос строится конкатенацией строк или через fmt.Sprintf с пользовательским вводом. Предотвращается использованием параметризованных запросов (database/sql с плейсхолдерами ? или $1), валидацией и экранированием входных данных, а также принципом наименьших привилегий для БД-пользователя. В Go нет магической защиты - ответственность на разработчике.
Подробное объяснение
SQL-инъекция возникает, когда непроверенные пользовательские данные попадают в текст SQL-запроса. Атакующий может изменить структуру запроса, добавив OR 1=1, UNION SELECT, комментарии -- или вложенные подзапросы. В Go типичный вектор - использование fmt.Sprintf("SELECT * FROM users WHERE id = %s", userInput) или конкатенация строк.
Параметризованные запросы (PreparedStatement) решают проблему на уровне драйвера: значения передаются отдельно от SQL-кода, и драйвер экранирует их как литералы. В database/sql это выглядит как db.Query("SELECT * FROM users WHERE id = ?", id) для MySQL или $1 для PostgreSQL. Важно: параметризация работает только для значений, не для идентификаторов (имён таблиц, колонок) - их нужно валидировать отдельно через whitelist.
Дополнительные меры: валидация типов и форматов на уровне приложения (например, strconv.Atoi для чисел), использование ORM с параметризацией по умолчанию (GORM, sqlx), ограничение прав БД-пользователя (только SELECT для чтения, отдельный пользователь для записи), логирование и мониторинг подозрительных запросов.
На практике
В Go с database/sql всегда используйте плейсхолдеры. Для динамических частей SQL (ORDER BY, LIMIT) применяйте whitelist-маппинг: map[string]string{"name": "name", "id": "id"} и проверяйте ввод по ключу. Для LIKE-запросов экранируйте % и _ в пользовательском вводе перед подстановкой как параметр. Для массовых вставок используйте Batch из pgx или цикл с prepared statements.
Не полагайтесь на экранирование через strings.Replace - это ненадёжно. Используйте sql.Named для именованных параметров, если нужно больше читаемости. Для сложных фильтров - стройте WHERE-условия динамически, но значения всегда через параметры.
Пример кода
GO// Плохо: инъекцияid := r.URL.Query().Get("id")rows, err := db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = %s", id))// Хорошо: параметризованный запросid := r.URL.Query().Get("id")rows, err := db.Query("SELECT * FROM users WHERE id = ?", id)// Динамический ORDER BY через whitelistallowedOrder := map[string]string{"name": "name","id": "id",}orderBy, ok := allowedOrder[r.URL.Query().Get("sort")]if !ok {orderBy = "id"}rows, err := db.Query("SELECT * FROM users ORDER BY "+orderBy, limit)
Как отвечать на собеседовании
Начните с прямого ответа "да, возможна", затем кратко объясните механизм. Покажите понимание различий между параметризацией и экранированием. Упомяните, что в Go нет встроенной защиты, но database/sql предоставляет безопасный API. Приведите пример плохого и хорошего кода. Если спросят про динамические части запроса - расскажите про whitelist. Завершите упоминанием дополнительных мер: валидация, права БД, мониторинг.
Что проверяет интервьюер
- Понимание сути инъекции, а не заученных ответов
- Умение применять параметризацию в Go на практике
- Знание ограничений параметризации (идентификаторы, LIKE)
- Осознание ответственности разработчика за безопасность
- Способность рассуждать о trade-off между удобством и безопасностью
Типичные ошибки
- Утверждение, что Go защищает от инъекций "из коробки"
- Предложение экранировать строки через
strings.Replaceкак основную защиту - Использование параметризации для имён таблиц/колонок без whitelist
- Игнорирование LIKE-запросов с
%и_ - Ответ без примера кода - интервьюер ждёт конкретики
- Смешивание понятий "валидация" и "параметризация" - это разные уровни защиты
> Похожие задачи по Go
Как определить дедлок в Go и когда он возникает?
Почему в канале Go без мьютекса не возникает проблем с конкурентным доступом?
Какие приятные и неприятные моменты в работе программиста
Зачем запускать много горутин на процессоре с ограниченным числом ядер
> Похожие задачи по backend
Как определить дедлок в Go и когда он возникает?
Почему в канале Go без мьютекса не возникает проблем с конкурентным доступом?
Какие приятные и неприятные моменты в работе программиста
Зачем запускать много горутин на процессоре с ограниченным числом ядер
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью