Найдите и объясните уязвимость в примере PHP: $q = "SELECT * FROM users WHERE name = '".$_GET['name']."'"; $r = mysqli_query($db,$q); — покажите, как выполняется SQL‑инъекция, предложите безопасные исправления и опишите общую стратегию предотвращения подобных уязвимостей в веб‑приложениях
Уязвимость: прямое включение пользовательского ввода в SQL-запрос через конкатенацию строк — классическая SQL‑инъекция. В коде $q = "SELECT * FROM users WHERE name = '".$_GET['name']."'"; никакая проверка/экранирование не делается, поэтому злоумышленник контролирует структуру запроса. Как выполняется инъекция (пример). Если запрос получает параметр name = anything' OR '1'='1 то итоговая строка станет: SELECT * FROM users WHERE name = 'anything' OR '1'='1' и условие всегда истинно, потому что ′1=1′'1=1'′1=1′. В результате вернутся все строки таблицы. Аналогично можно использовать комментарии (`--`, `#`) и UNION для вытягивания других полей: name = a' UNION SELECT password FROM users -- Безопасные исправления (рекомендуемый порядок): 1) Параметризованные запросы (prepared statements) — предпочтительный способ. - MySQLi (процедурный): $stm = mysqli_prepare($db, "SELECT * FROM users WHERE name = ?"); mysqli_stmt_bind_param($stm, "s", $_GET['name']); mysqli_stmt_execute($stm); $res = mysqli_stmt_get_result($stm); - PDO: $stm = $pdo->prepare("SELECT * FROM users WHERE name = :name"); $stm->execute([':name' => $_GET['name']]); $res = $stm->fetchAll(); 2) Если параметр — число, применяйте строгую фильтрацию/каст: $id = (int)$_GET['id']; // безопасно в плане SQL для целых $q = "SELECT * FROM items WHERE id = ".$id; 3) Как временная (менее предпочтительная) мера — экранирование: $name = mysqli_real_escape_string($db, $_GET['name']); $q = "SELECT * FROM users WHERE name = '".$name."'"; Но экранирование сложнее и легче ошибиться (кодировка, забытые места), поэтому используйте prepared statements. Общая стратегия предотвращения подобных уязвимостей: - Всегда использовать параметризованные запросы/ORM с автоматическим биндингом параметров. - Валидировать и нормализовать вход (белый список, строгие типы). - Минимальные привилегии для учётной записи БД (нет прав DROP/ADMIN если нужно только SELECT/INSERT/UPDATE). - Логирование и мониторинг подозрительных запросов, тестирование (SAST/DAST, pentest). - Обновления библиотек/СУБД, защита от утечек (шифрование чувствительных полей). - Веб‑фильтры/WAF как дополнительный уровень защиты. Коротко: не конкатенируйте пользовательский ввод в SQL — используйте подготовленные выражения и валидацию входных данных.
$q = "SELECT * FROM users WHERE name = '".$_GET['name']."'";
никакая проверка/экранирование не делается, поэтому злоумышленник контролирует структуру запроса.
Как выполняется инъекция (пример). Если запрос получает параметр
name = anything' OR '1'='1
то итоговая строка станет:
SELECT * FROM users WHERE name = 'anything' OR '1'='1'
и условие всегда истинно, потому что ′1=1′'1=1'′1=1′. В результате вернутся все строки таблицы. Аналогично можно использовать комментарии (`--`, `#`) и UNION для вытягивания других полей:
name = a' UNION SELECT password FROM users --
Безопасные исправления (рекомендуемый порядок):
1) Параметризованные запросы (prepared statements) — предпочтительный способ.
- MySQLi (процедурный):
$stm = mysqli_prepare($db, "SELECT * FROM users WHERE name = ?");
mysqli_stmt_bind_param($stm, "s", $_GET['name']);
mysqli_stmt_execute($stm);
$res = mysqli_stmt_get_result($stm);
- PDO:
$stm = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stm->execute([':name' => $_GET['name']]);
$res = $stm->fetchAll();
2) Если параметр — число, применяйте строгую фильтрацию/каст:
$id = (int)$_GET['id']; // безопасно в плане SQL для целых
$q = "SELECT * FROM items WHERE id = ".$id;
3) Как временная (менее предпочтительная) мера — экранирование:
$name = mysqli_real_escape_string($db, $_GET['name']);
$q = "SELECT * FROM users WHERE name = '".$name."'";
Но экранирование сложнее и легче ошибиться (кодировка, забытые места), поэтому используйте prepared statements.
Общая стратегия предотвращения подобных уязвимостей:
- Всегда использовать параметризованные запросы/ORM с автоматическим биндингом параметров.
- Валидировать и нормализовать вход (белый список, строгие типы).
- Минимальные привилегии для учётной записи БД (нет прав DROP/ADMIN если нужно только SELECT/INSERT/UPDATE).
- Логирование и мониторинг подозрительных запросов, тестирование (SAST/DAST, pentest).
- Обновления библиотек/СУБД, защита от утечек (шифрование чувствительных полей).
- Веб‑фильтры/WAF как дополнительный уровень защиты.
Коротко: не конкатенируйте пользовательский ввод в SQL — используйте подготовленные выражения и валидацию входных данных.