Найдите уязвимость в PHP-фрагменте: $q = "SELECT * FROM users WHERE name='".$_GET['name']."'"; — объясните возможную атаку и как правильно защититься с примерами подготовленных выражений
Уязвимость: конкатенация пользовательского ввода в SQL — SQL‑инъекция. В строке $q = "SELECT * FROM users WHERE name='".$_GET['name']."'"; взломщик может подставить такой параметр GET. Пример атаки: - Передать в параметре name строку: `' OR '1'='1' --` - Тогда итоговый SQL станет, например: SELECT * FROM users WHERE name='' OR ′1′=′1′'1'='1'′1′=′1′ -- ' (условие ′1′=′1′'1'='1'′1′=′1′ всегда истинно, комментарий `--` отсекает остаток запроса). Последствия: вытягивание всех записей, обход аутентификации, изменение/удаление данных, эксфильтрация конфиденциальной информации и т.д. Правильная защита — подготовленные выражения (prepared statements) с привязкой параметров. Примеры. PDO: <?php $pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, // использовать нативные prepared statements ]); $stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name"); $stmt->execute([':name' => $_GET['name']]); // параметр безопасно передан $user = $stmt->fetch(PDO::FETCH_ASSOC); ?>
MySQLi (object‑oriented): <?php $mysqli = new mysqli('localhost', 'user', 'pass', 'test'); $stmt = $mysqli->prepare("SELECT * FROM users WHERE name = ?"); $stmt->bind_param("s", $_GET['name']); // "s" — строковый параметр $stmt->execute(); $result = $stmt->get_result(); $user = $result->fetch_assoc(); ?>
Краткие рекомендации: - Всегда использовать подготовленные выражения (PDO или MySQLi) вместо конкатенации. - Проверять/фильтровать и валидировать вход (длина, допустимые символы) по бизнес‑логике. - Минимизировать права БД у приложения (не использовать root). - Для LIKE экранировать метасимволы или формировать паттерн через параметр: $stmt->execute([':name' => "%$safeName%"]); - По возможности установить PDO::ATTR_EMULATE_PREPARES = false, чтобы использовать нативные prepares. Этого достаточно, чтобы устранить описанную уязвимость.
$q = "SELECT * FROM users WHERE name='".$_GET['name']."'";
взломщик может подставить такой параметр GET.
Пример атаки:
- Передать в параметре name строку: `' OR '1'='1' --`
- Тогда итоговый SQL станет, например:
SELECT * FROM users WHERE name='' OR ′1′=′1′'1'='1'′1′=′1′ -- '
(условие ′1′=′1′'1'='1'′1′=′1′ всегда истинно, комментарий `--` отсекает остаток запроса).
Последствия: вытягивание всех записей, обход аутентификации, изменение/удаление данных, эксфильтрация конфиденциальной информации и т.д.
Правильная защита — подготовленные выражения (prepared statements) с привязкой параметров. Примеры.
PDO:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // использовать нативные prepared statements
]);
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute([':name' => $_GET['name']]); // параметр безопасно передан
$user = $stmt->fetch(PDO::FETCH_ASSOC);
?>
MySQLi (object‑oriented):
<?php
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$stmt = $mysqli->prepare("SELECT * FROM users WHERE name = ?");
$stmt->bind_param("s", $_GET['name']); // "s" — строковый параметр
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
?>
Краткие рекомендации:
- Всегда использовать подготовленные выражения (PDO или MySQLi) вместо конкатенации.
- Проверять/фильтровать и валидировать вход (длина, допустимые символы) по бизнес‑логике.
- Минимизировать права БД у приложения (не использовать root).
- Для LIKE экранировать метасимволы или формировать паттерн через параметр:
$stmt->execute([':name' => "%$safeName%"]);
- По возможности установить PDO::ATTR_EMULATE_PREPARES = false, чтобы использовать нативные prepares.
Этого достаточно, чтобы устранить описанную уязвимость.