Почему важно использовать параметризованные запросы вместо конкатенации строк?
Что проверяют
Понимаете ли механизм: почему плейсхолдер защищает, а ручное экранирование кавычек нет. И знаете ли, что параметром передать нельзя.
Как отвечать
При склейке строк текст запроса и данные пользователя смешиваются, и разборщик СУБД читает их вместе. Достаточно одной кавычки, чтобы значение стало частью синтаксиса. Плейсхолдер отправляет текст и значения отдельно: запрос разбирается до того, как значение до него доедет, и значение остаётся значением, что бы в нём ни лежало.
В Go это поведение по умолчанию у database/sql:
row := db.QueryRowContext(ctx,
"SELECT id, email FROM users WHERE id = $1", userID)Никакого fmt.Sprintf с текстом запроса. Конкатенация переменной внутрь SQL это находка для ревью, даже когда переменная кажется безопасной.
Что стоит добавить самому:
- плейсхолдер подставляет только значение. Имя таблицы, имя колонки и направление сортировки так передать нельзя, для них нужен список разрешённых вариантов;
- условие
INтребует сгенерировать нужное число плейсхолдеров либо передать массив одним параметром; - побочный плюс это переиспользование подготовленного запроса, но выигрыш зависит от драйвера и пулера соединений.
Где спотыкаются
Экранируют кавычки руками или вырезают опасные слова. Чёрные списки обходятся другой кодировкой, комментарием, регистром, а в числовом поле кавычки для инъекции вообще не нужны. Фильтрация никогда не заменяет разделение текста и данных.
Считают, что ORM защищает сама по себе. Любой сырой фрагмент, собранный строкой, возвращает дыру, и самое частое место это сортировка по имени поля, пришедшему из запроса пользователя.
Обещают ускорение от плейсхолдеров всегда. Подготовленный запрос может получить общий план, который для перекошенного распределения данных хуже плана под конкретное значение. За скорость отвечают индексы и статистика, параметры отвечают за безопасность.