Наиболее надёжный путь — всегда использовать параметризованные запросы или подготовленные выражения (prepared statements), а НЕ формировать запросы через простую конкатенацию строк с пользовательскими значениями.
Для более сложных сценариев (динамический SQL внутри процедур) — применяйте специальные механизмы экранирования и whitelisting (строгую фильтрацию) параметров.
cursor.execute('SELECT * FROM users WHERE login = %s', [login])
EXECUTE format('SELECT * FROM %I WHERE id = $1', tablename) USING id;
Здесь %I подставляет только имена таблиц/столбцов безопасным образом.
Безопасен ли следующий подход при вставке числа в строку?
EXECUTE 'SELECT * FROM users WHERE id = ' || user_input;
НЕТ! Даже если ожидаете число, злоумышленник может передать код:
1; DROP TABLE users; — запрос будет выполнен. Поэтому всегда используйте плейсхолдеры и явную проверку типа входных параметров.
История 1
Форма поиска по сотрудникам строила WHERE-условия через конкатенацию строк на стороне приложения. Злоумышленник ввёл: ' OR 1=1 --, что вывело данные всех сотрудников. Позже через аналогичный подход был удалён раздел данных. Вывод: конкатенация значимых параметров — всегда риск.
История 2
В административном интерфейсе выбора отчёта название таблицы подтягивалось из пользовательского поля и вставлялось в SQL-запрос. Пользователь сумел вставить невалидное имя и получить доступ к системным таблицам. После этого разрешили только жёстко заданные имена (whitelisting).
История 3
В e-commerce проекте при динамической сортировке пользователи передавали имя поля по GET-параметру. Хакер подставил price; DELETE FROM orders; --, что привело к потере всех заказов. Фильтрация допустимых имён столбцов и использование параметризованных запросов решили проблему.