Ответ
Основной и самый надежный способ защиты от SQL-инъекций — это использование подготовленных выражений (prepared statements) с параметризованными запросами. Этот подход разделяет саму SQL-команду и данные, которые в нее подставляются. Драйвер базы данных отправляет их серверу раздельно, что исключает возможность интерпретации пользовательского ввода как части SQL-кода.
Пример с database/sql
:
// ? является плейсхолдером для параметра
stmt, err := db.Prepare("SELECT id, name FROM users WHERE email = ?")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
// Передаем пользовательский ввод как параметр, а не вставляем в строку запроса
rows, err := stmt.Query(emailInput)
// ...
Дополнительные, но не менее важные, меры:
- Использование ORM: Библиотеки, такие как GORM или sqlc, по умолчанию используют подготовленные выражения, что снижает риск ошибки.
- Валидация и санация входных данных: Всегда проверяйте и очищайте данные, поступающие от пользователя, на соответствие ожидаемому формату (например, что ID — это число, а email — валидный адрес).
- Принцип наименьших привилегий: Предоставляйте пользователю базы данных только те права, которые ему действительно необходимы. Например, пользователю, который только читает данные, не нужны права на
UPDATE
илиDELETE
. - Избегайте конкатенации строк: Никогда не создавайте SQL-запросы путем простого сложения строк с пользовательским вводом. Это прямой путь к уязвимости.
Для динамического построения запросов, где количество условий заранее неизвестно, используйте специальные библиотеки-конструкторы запросов (query builders), например, Squirrel или sqlx, которые помогают безопасно формировать сложные запросы.