Jomel.Tr

Web Vulnerabilities — Go

Web Vulnerabilities — Go

Прямая конкатенация пользовательского ввода в SQL-запрос.

! vulnerable.go
func GetUser(db *sql.DB, id string) (*User, error) {
    // id может быть: 1 OR 1=1 --
    query := "SELECT * FROM users WHERE id = " + id
    row := db.QueryRow(query)
    var u User
    err := row.Scan(&u.ID, &u.Name, &u.Email)
    return &u, err
}
secure.go
func GetUser(db *sql.DB, id string) (*User, error) {
    // Параметризованный запрос — id всегда данные, не код
    query := "SELECT * FROM users WHERE id = $1"
    row := db.QueryRow(query, id)
    var u User
    err := row.Scan(&u.ID, &u.Name, &u.Email)
    return &u, err
}

Как исправить

Никогда не склеивайте SQL-строки с пользовательским вводом. Используйте только параметризованные запросы (placeholders $1, ?), при которых драйвер передаёт данные отдельно от тела запроса — ввод физически не может стать частью кода. Идентификаторы таблиц/колонок, которые нельзя параметризовать, проверяйте по allowlist. Права БД выдавайте по принципу наименьших привилегий.

Инструменты и практики

  • database/sql + placeholders — Стандартная библиотека: db.Query("... WHERE id = $1", id). Базовый и достаточный для большинства случаев способ.
  • sqlc — Генерирует типобезопасный Go-код из обычного SQL на этапе сборки. Запросы проверяются компилятором, инъекции исключены by design.
  • ent (entgo.io) — ORM от Meta с кодогенерацией и типобезопасным query-builder. Граф-ориентированная схема, никаких сырых строк.
  • GORM — Популярный full-feature ORM. Параметризует автоматически; избегайте Raw/Exec с конкатенацией.
  • sqlx / squirrel — sqlx — тонкая надстройка над database/sql; squirrel — безопасный query-builder, собирающий параметризованные запросы.
  • pgx — Высокопроизводительный драйвер PostgreSQL с нативной поддержкой prepared statements и protocol-level биндингом.