Разберите SQL-запрос: `SELECT * FROM users WHERE name = '` || name || `'` — объясните риски, механизмы SQL-инъекций и стратегии безопасной работы с параметрами
Коротко — проблема в том, что выражение `SELECT * FROM users WHERE name = '` || name || `'` формирует SQL путём простого склеивания пользовательской строки: если `name` контролирует злоумышленник, он может подменить структуру запроса (SQL‑инъекция). Что происходит (пример) - Если злоумышленник передаст `name = a' OR '1'='1`, итоговый SQL станет: `SELECT * FROM users WHERE name = 'a' OR '1'='1'` Здесь выражение `1=11=11=1` — всегда истинно, результат: возвращаются все строки (аутентификация/фильтрация обходятся). Механизмы и типы атак (кратко) - Разрыв литерала и вставка логики — закрыть кавычку, добавить `OR`, `AND`, операции сравнения. - Комментарии — `--`, `/* ... */` для обрезки оставшейся части запроса. - UNION‑инъекции — добавить `UNION SELECT ...` для вытаскивания данных из других таблиц. - Стеки запросов (если СУБД поддерживает) — добавить `; DROP TABLE ...`. - In‑band (error/union) — получать данные прямо в ответе. - Blind (boolean/time‑based) — извлекать данные побитово через поведенческие ответы или паузы. - Out‑of‑band — использовать внешние каналы (DNS, HTTP) для вывода данных. Последствия - Утечка конфиденциальных данных, обход авторизации, изменение/удаление данных, получение удалённого выполнения команд через расширения СУБД, компрометация всей БД. Стратегии безопасной работы (порядок предпочтения) 1. Параметризованные запросы / подготовленные выражения (Prepared Statements) - Пример шаблона: `SELECT * FROM users WHERE name = ?` или `WHERE name = $1` или `WHERE name = :name`. - Параметры передаются отдельно и не интерпретируются как SQL, поэтому инъекции блокируются. - Примеры: в Java `PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?"); ps.setString(1, name);` в Python (psycopg2) `cur.execute("SELECT * FROM users WHERE name = %s", (name,))`. 2. Хранимые процедуры с параметрами (только если они действительно используют параметры, а не строят динамический SQL). 3. ORM с параметризацией — использовать API ORM для фильтрации, а не формировать raw SQL вручную. 4. Валидация и белый список — для ограниченных полей (например, статус, роль, идентификатор) проверять соответствие регуляркам/списку допустимых значений. 5. Экранирование — использовать проверенные функциональные экранирующие функции СУБД как запасной вариант (но не надёжнее параметризации). 6. Минимизация прав — аккаунт БД для приложения должен иметь только нужные привилегии (например, запрет на DROP). 7. Ограничения в выводе и лимиты — возвращать только нужные колонки, добавлять LIMIT. 8. Логирование и мониторинг — отслеживать аномальные запросы/ошибки, WAF как дополнительная защита. Резюме (коротко) - Никогда не конкатенируйте сырые пользовательские строки в SQL. - Используйте подготовленные выражения/параметры — это основное и простое средство защиты. - Дополняйте валидацией, минимальными правами и мониторингом для снижения риска и ущерба.
`SELECT * FROM users WHERE name = '` || name || `'`
формирует SQL путём простого склеивания пользовательской строки: если `name` контролирует злоумышленник, он может подменить структуру запроса (SQL‑инъекция).
Что происходит (пример)
- Если злоумышленник передаст `name = a' OR '1'='1`, итоговый SQL станет:
`SELECT * FROM users WHERE name = 'a' OR '1'='1'`
Здесь выражение `1=11=11=1` — всегда истинно, результат: возвращаются все строки (аутентификация/фильтрация обходятся).
Механизмы и типы атак (кратко)
- Разрыв литерала и вставка логики — закрыть кавычку, добавить `OR`, `AND`, операции сравнения.
- Комментарии — `--`, `/* ... */` для обрезки оставшейся части запроса.
- UNION‑инъекции — добавить `UNION SELECT ...` для вытаскивания данных из других таблиц.
- Стеки запросов (если СУБД поддерживает) — добавить `; DROP TABLE ...`.
- In‑band (error/union) — получать данные прямо в ответе.
- Blind (boolean/time‑based) — извлекать данные побитово через поведенческие ответы или паузы.
- Out‑of‑band — использовать внешние каналы (DNS, HTTP) для вывода данных.
Последствия
- Утечка конфиденциальных данных, обход авторизации, изменение/удаление данных, получение удалённого выполнения команд через расширения СУБД, компрометация всей БД.
Стратегии безопасной работы (порядок предпочтения)
1. Параметризованные запросы / подготовленные выражения (Prepared Statements)
- Пример шаблона: `SELECT * FROM users WHERE name = ?` или `WHERE name = $1` или `WHERE name = :name`.
- Параметры передаются отдельно и не интерпретируются как SQL, поэтому инъекции блокируются.
- Примеры: в Java `PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?"); ps.setString(1, name);`
в Python (psycopg2) `cur.execute("SELECT * FROM users WHERE name = %s", (name,))`.
2. Хранимые процедуры с параметрами (только если они действительно используют параметры, а не строят динамический SQL).
3. ORM с параметризацией — использовать API ORM для фильтрации, а не формировать raw SQL вручную.
4. Валидация и белый список — для ограниченных полей (например, статус, роль, идентификатор) проверять соответствие регуляркам/списку допустимых значений.
5. Экранирование — использовать проверенные функциональные экранирующие функции СУБД как запасной вариант (но не надёжнее параметризации).
6. Минимизация прав — аккаунт БД для приложения должен иметь только нужные привилегии (например, запрет на DROP).
7. Ограничения в выводе и лимиты — возвращать только нужные колонки, добавлять LIMIT.
8. Логирование и мониторинг — отслеживать аномальные запросы/ошибки, WAF как дополнительная защита.
Резюме (коротко)
- Никогда не конкатенируйте сырые пользовательские строки в SQL.
- Используйте подготовленные выражения/параметры — это основное и простое средство защиты.
- Дополняйте валидацией, минимальными правами и мониторингом для снижения риска и ущерба.