FlawOpen

flawopen.com/SQL Injection/Достаточно ли экранирования?

Защищает ли экранирование кавычек от SQL Injection?

CWE-89: SQL InjectionReference page
Краткий ответ

Обычно нет. Функция экранирования зависит от СУБД, кодировки соединения, режима SQL и точного контекста кавычек. Параметризованные запросы отделяют значения от синтаксиса SQL через API драйвера. Значения передавайте параметрами; динамические идентификаторы, которые нельзя параметризовать, выбирайте из фиксированного списка приложения.

Почему экранирование ненадёжно на практике

Кодировка соединения влияет на экранирование

Экранирование — не контекстно-независимая замена текста. MySQL указывает, что mysql_real_escape_string() использует кодировку соединения, а SET NAMES не обновляет состояние клиентской библиотеки, которое использует эта функция. Несовпадение кодировок может нарушить предположения о защищённом тексте. Предпочитайте параметризованные API; если старый код пока требует экранирования, применяйте поддерживаемую функцию драйвера с правильно настроенной кодировкой и обрабатывайте ошибки.

Пропущенный вызов ослабляет всю защиту

Экранирование нужно корректно применять при каждой интерполяции с учётом драйвера, кодировки, режима SQL и контекста литерала. Параметризованные API явно отделяют значение от данных в вызове запроса и избавляют от ручной сборки строки в кавычках.

Кавычки не покрывают все контексты SQL

Экранирование кавычек затрагивает только символы внутри конкретного строкового литерала. Оно не создаёт безопасные имена таблиц и столбцов, ключевые слова или направление сортировки и не защищает ввод в некавыченных числовых выражениях. Параметризуйте значения, а динамическую структуру выбирайте из фиксированных вариантов приложения.

VULNERABLE
// Пользовательский ввод вставляется в синтаксис SQL
query = f"SELECT id FROM users WHERE name = '{name}'"
cursor.execute(query)
HARDENED
// Драйвер связывает name как значение данных
cursor.execute(
    "SELECT id FROM users WHERE name = ?",
    (name,),
)

Что меняет привязка параметров

Параметризованный запрос передаёт структуру SQL и значения как отдельные входы через API базы данных. Драйвер может использовать нативные подготовленные запросы или другую безопасную реализацию; не предполагайте конкретную последовательность протокола. Важно, что значение считается данными, а не повторно разбирается как синтаксис SQL. В Python DB-API используйте плейсхолдер драйвера и передавайте значения отдельно; не формируйте запрос строковым форматированием.

Инженерный контрольный список

Частые вопросы

Может ли экранирование быть правильным инструментом?

Для идентификаторов или SQL-фрагментов, которые нельзя передать параметром, используйте только поддерживаемую драйвером функцию quoting вместе с фиксированным списком приложения. Не применяйте общее экранирование к произвольным значениям.

Безопасна ли поддерживаемая функция экранирования драйвера?

Она может помочь в документированном контексте, но зависит от СУБД, настроек соединения, контекста кавычек и правильного применения в каждом месте. Параметризованные запросы остаются более безопасным вариантом по умолчанию для значений.

Источники

См. также SQL-инъекции (CWE-89): как они работают и как их предотвратить в любом языке — flawopen.com Достаточно ли ORM, чтобы предотвратить SQL-инъекции? Защищает ли Knex.js от SQL-инъекций? MyBatis ${} и #{}: защита от SQL Injection MySQLi и PDO: безопасные подготовленные запросы Защищает ли NHibernate от SQL-инъекций? NoSQL-инъекция в MongoDB: безопасные фильтры