Проанализируйте уязвимость SQL-инъекции на примере PHP-кода: $query = "SELECT * FROM users WHERE name = '$name'"; — как правильно защититься при помощи подготовленных выражений, ORM и иных практик?

11 Янв в 06:34
28 +1
0
Ответы
1
Кратко: уязвимость в строке
$query = "SELECT * FROM users WHERE name = '$name'";
возникает потому, что пользовательский ввод попадает в SQL без разделения кода и данных — злоумышленник может подставить нагрузку вроде "' OR '1'='1" (т.е. ′1′=′1′'1'='1'1=1) и получить нежелательный результат (например, все строки).
Как правильно защититься — практики и примеры.
1) Подготовленные выражения (PDO)
- Преимущество: драйвер отделяет код от данных, параметры передаются безопасно.
Пример:
$pdo = new PDO(...);
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute([':name' => $name]);
$rows = $stmt->fetchAll();
альтернатива с позиционным параметром:
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ?");
$stmt->execute([$name]);
Если нужен явный тип:
$stmt->bindValue(':name', $name, PDO::PARAM_STR);
2) Подготовленные выражения (mysqli)
Пример:
$mysqli = new mysqli(...);
$stmt = $mysqli->prepare("SELECT * FROM users WHERE name = ?");
$stmt->bind_param("s", $name); // "s" — строка
$stmt->execute();
$result = $stmt->get_result();
3) ORM / Query Builder
- ORM автоматически параметризует запросы (если используется корректно), что уменьшает риск SQLi.
Laravel (Eloquent / Query Builder):
$users = DB::table('users')->where('name', $name)->get();
или
$users = User::where('name', $name)->get();
Doctrine QueryBuilder:
$qb->select('u')->from('User','u')->where('u.name = :name')->setParameter('name',$name);
4) Особенности и дополнительные меры
- Никогда не формируйте SQL конкатенацией с невалидированными входными данными.
- Не пытайтесь «экранировать» ввод вручную как основную защиту (addslashes, некорректное mysql_real_escape_string) — используйте подготовленные выражения.
- Для числовых идентификаторов приводите к типу: $id = (int)$_GET['id']; (явное приведение типов уменьшает риск).
- Для динамических идентификаторов (имена таблиц/столбцов) используйте белые списки (allowlist), т. е. проверяйте, что значение находится в допустимом наборе, т.к. параметры не могут подставлять идентификаторы.
- Для IN(...) — формируйте нужное число плейсхолдеров:
$in = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN ($in)");
$stmt->execute($ids);
5) Операционные и политики безопасности
- Используйте учетную запись БД с минимумом прав (least privilege).
- Логируйте подозрительные запросы и включите мониторинг/IDS/WAF.
- Не показывайте пользователям подробные SQL-ошибки (скрывайте стектрейсы).
- Храните чувствительные данные (пароли) в виде хэшей (bcrypt/argon2), а не в открытом виде.
Вывод: главный принцип — никогда не вставлять необработанный ввод прямо в SQL. Используйте подготовленные выражения (PDO/mysqli), ORM или тщательно реализованные белые списки для динамических частей запроса, а также дополнительные практики безопасности (приведение типов, минимальные привилегии, логирование).
11 Янв в 06:42
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир