Код-ревью Middle Инъекции: SQL, NoSQL, команды обновлено

Ревью: обработчик на Go с базой и командой

Вопрос

Найдите уязвимости в HTTP-обработчике.

func handler(w http.ResponseWriter, r *http.Request) {
	user := r.URL.Query().Get("user")
	host := r.URL.Query().Get("host")
	q := fmt.Sprintf("SELECT id, email FROM users WHERE login = '%s'", user)
	row := db.QueryRow(q)
	var id int
	var email string
	row.Scan(&id, &email)
	out, _ := exec.Command("sh", "-c", "ping -c 1 "+host).Output()
	fmt.Fprintf(w, "%d %s %s", id, email, out)
}

Коротко

В Go параметры передаются плейсхолдерами драйвера ($1 для PostgreSQL, ? для MySQL), а команды через exec.Command с отдельными аргументами без шелла. Игнорирование ошибок тоже бывает уязвимостью: обработчик продолжает работу в неожиданном состоянии.

Что должен найти ревьюер

  1. Безопасностьстрока 4
    SQL-инъекция: fmt.Sprintf вклеивает user в запрос. Нужно db.QueryRow("... WHERE login = $1", user).
  2. Ошибкастрока 8
    Ошибка Scan игнорируется: при отсутствии пользователя ответ с нулевыми значениями.
  3. Безопасностьстрока 9
    Инъекция команд: sh -c с конкатенацией host. Нужно exec.Command("ping", "-c", "1", host) и проверка, что host это IP или допустимое имя.
  4. Ошибкастрока 9
    Ошибка выполнения команды игнорируется.
  5. Безопасностьстрока 10
    Нет авторизации: кто угодно получает email любого пользователя по логину.

Разбор

В Go параметры передаются плейсхолдерами драйвера ($1 для PostgreSQL, ? для MySQL), а команды через exec.Command с отдельными аргументами без шелла. Игнорирование ошибок тоже бывает уязвимостью: обработчик продолжает работу в неожиданном состоянии.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.