Разберите SQL-кейс: пользовательский ввод подставляют в строку запроса SELECT * FROM users WHERE name = ' " + name + " '; — какие уязвимости здесь есть и как правильно защититься
Коротко — у кода типа SELECT * FROM users WHERE name = '" + name + "'; есть классическая уязвимость SQL‑инъекции: ввод пользователя попадает в текст запроса без проверки или привязки, поэтому злоумышленник может изменить семантику запроса (таутологии, UNION, stacked queries, blind‑/timing‑атаки и т.д.) и получить/изменить данные, обойти аутентификацию, получить структуру БД или выполнить нежелательные команды. Почему это опасно (примеры): - name = "' OR '1'='1" даст WHERE name = '' OR '1'='1' — вернёт все пользователи. - name = "'; DROP TABLE users; --" (если СУБД поддерживает несколько команд) может удалить таблицу. - возможна утечка через ошибки, побочные каналы (тайминги), second‑order injection (ввод хранится, потом используется в другом запросе). Как правильно защищаться (основное правило — никогда не складывать SQL из строк с пользовательским вводом): - Использовать параметризованные запросы / Prepared Statements (bind parameters). Примеры: PHP (PDO): $stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name"); $stmt->execute([':name' => $name]); Python (psycopg2): cur.execute("SELECT * FROM users WHERE name = %s", (name,)) Java (JDBC): PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?"); ps.setString(1, name); ResultSet rs = ps.executeQuery(); - Для LIKE использовать параметры и экранировать метасимволы (%, _) через механизм БД или вручную, не подставлять напрямую. - Если нужно вставлять идентификаторы (имя таблицы/колонки), не параметризуем их — применять строгое белое список и мэппинг (name -> конкретное безопасное имя). - В крайнем случае (если нельзя использовать подготовленные выражения) — применять специализированные DB‑escape функции (например, mysqli_real_escape_string) и обязательно устанавливать корректную кодировку соединения; но это менее безопасно и легко ошибочно. - Минимальные привилегии для учётной записи БД, логирование и мониторинг запросов, ограничение выдаваемых колонок (не SELECT *), лимиты на количество возвращаемых строк. - Отключить многокомандные запросы, не показывать подробные ошибки БД пользователю, использовать WAF и регулярно проводить тестирование (сканеры, pentest). Дополнительно: - Хранимые процедуры безопасны только если параметры не конкатенируются внутри них. - Проверяйте и нормализуйте кодировку соединения (UTF‑8) — проблемы с кодировками могут обходить экранирование. - Тестируйте приложение на SQL‑инъекции (автоматизированные и ручные тесты). Вывод: исправление — перестать конкатенировать строки и применять подготовленные параметры + ограничивать права и валидировать/выполнять белые списки там, где параметры невозможны.
SELECT * FROM users WHERE name = '" + name + "';
есть классическая уязвимость SQL‑инъекции: ввод пользователя попадает в текст запроса без проверки или привязки, поэтому злоумышленник может изменить семантику запроса (таутологии, UNION, stacked queries, blind‑/timing‑атаки и т.д.) и получить/изменить данные, обойти аутентификацию, получить структуру БД или выполнить нежелательные команды.
Почему это опасно (примеры):
- name = "' OR '1'='1" даст WHERE name = '' OR '1'='1' — вернёт все пользователи.
- name = "'; DROP TABLE users; --" (если СУБД поддерживает несколько команд) может удалить таблицу.
- возможна утечка через ошибки, побочные каналы (тайминги), second‑order injection (ввод хранится, потом используется в другом запросе).
Как правильно защищаться (основное правило — никогда не складывать SQL из строк с пользовательским вводом):
- Использовать параметризованные запросы / Prepared Statements (bind parameters). Примеры:
PHP (PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute([':name' => $name]);
Python (psycopg2):
cur.execute("SELECT * FROM users WHERE name = %s", (name,))
Java (JDBC):
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE name = ?");
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
- Для LIKE использовать параметры и экранировать метасимволы (%, _) через механизм БД или вручную, не подставлять напрямую.
- Если нужно вставлять идентификаторы (имя таблицы/колонки), не параметризуем их — применять строгое белое список и мэппинг (name -> конкретное безопасное имя).
- В крайнем случае (если нельзя использовать подготовленные выражения) — применять специализированные DB‑escape функции (например, mysqli_real_escape_string) и обязательно устанавливать корректную кодировку соединения; но это менее безопасно и легко ошибочно.
- Минимальные привилегии для учётной записи БД, логирование и мониторинг запросов, ограничение выдаваемых колонок (не SELECT *), лимиты на количество возвращаемых строк.
- Отключить многокомандные запросы, не показывать подробные ошибки БД пользователю, использовать WAF и регулярно проводить тестирование (сканеры, pentest).
Дополнительно:
- Хранимые процедуры безопасны только если параметры не конкатенируются внутри них.
- Проверяйте и нормализуйте кодировку соединения (UTF‑8) — проблемы с кодировками могут обходить экранирование.
- Тестируйте приложение на SQL‑инъекции (автоматизированные и ручные тесты).
Вывод: исправление — перестать конкатенировать строки и применять подготовленные параметры + ограничивать права и валидировать/выполнять белые списки там, где параметры невозможны.