В веб‑форме используется фрагмент PHP: $query = "SELECT * FROM users WHERE name = '" . $_GET['name'] . "'"; — покажите возможную уязвимость, варианты атак и способы защиты, включая подготовленные выражения и валидацию
Уязвимость - В коде $query = "SELECT * FROM users WHERE name = '" . $_GET['name'] . "'"; — введённые пользователем данные вставляются в SQL напрямую → SQL‑инъекция. Злоумышленник может подменить структуру запроса. Примеры атак (payload — что добавит злоумышленник) - Авторизация обходом: запрос превращается в проверку всех строк: "' OR '1'='1' --" (ядро проверки 1=11=11=1). - UNION‑инъекция для вытягивания данных: "' UNION SELECT credit_card,1 FROM payments --" (ядро использования 111 как столбца). - Разрушение/удаление: "'; DROP TABLE users; --" — если разрешены несколько команд. - Blind SQL injection: побитовое/логическое угадывание данных через время/ошибки (например, payload типа "' AND IF(SUBSTRING(password,1,1)='a', SLEEP(5), 0) --"). - Использование кодировок/обхода фильтров: экранирование, комментарии, байтовые последовательности. Последствия: утечка/изменение/удаление данных, обход авторизации, удалённое выполнение административных SQL‑команд. Способы защиты (по приоритету) 1. Параметризованные запросы (prepared statements) — основной и обязательный способ. - PDO: $pdo = new PDO(..., [PDO::ATTR_EMULATE_PREPARES => false]); $stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name"); $stmt->execute([':name' => $_GET['name']]); - mysqli: $stmt = $mysqli->prepare("SELECT * FROM users WHERE name = ?"); $stmt->bind_param("s", $_GET['name']); $stmt->execute(); Пояснение: параметры передаются отдельно от текста запроса, нельзя изменить структуру SQL. 2. Валидация и нормализация входа (white‑list): - Для имён — разрешить только буквы, пробелы и максимум N символов: проверка по регулярному выражению, ограничение длины. Пример: if (!preg_match('/^[\p{L}\- ]{1,100}$/u', $name)) { /* reject */ } - Для числовых полей — явно приводить к числу: $id = (int)$_GET['id']. Пояснение: whitelist над blacklist — надёжнее. 3. Экранирование (как вторичный метод): - mysqli_real_escape_string — уменьшает риск, но не заменяет подготовленные выражения. Использовать только если параметризованные запросы невозможны. 4. Отключить возможность выполнения нескольких запросов в одном вызове: - Не использовать mysqli_multi_query; в PDO по умолчанию многозапросы не выполняются. 5. Минимизация прав БД: - Аккаунт приложения должен иметь только необходимые права (SELECT/INSERT/UPDATE и т. п.), не должен иметь DROP/DELETE без нужды. 6. Настройки PDO: - Отключить эмуляцию подготовленных выражений: PDO::ATTR_EMULATE_PREPARES = false (чтобы реальные prepared statements использовались сервером). 7. Защита на уровне приложений и инфраструктуры: - Логи и мониторинг подозрительных запросов. - Web Application Firewall (WAF) как дополнительный барьер. - Прячьте подробные сообщения об ошибках от пользователя. Короткая демонстрация безопасного кода (PDO): $pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_EMULATE_PREPARES => false]); $name = $_GET['name']; // лучше пройти валидацию $stmt = $pdo->prepare("SELECT id, name, email FROM users WHERE name = :name"); $stmt->execute([':name' => $name]); $user = $stmt->fetch(); Резюме - Самое важное: никогда не вставлять сырые данные в SQL — используйте подготовленные выражения + валидацию (whitelist и ограничение длины) + минимальные права у БД.
- В коде $query = "SELECT * FROM users WHERE name = '" . $_GET['name'] . "'"; — введённые пользователем данные вставляются в SQL напрямую → SQL‑инъекция. Злоумышленник может подменить структуру запроса.
Примеры атак (payload — что добавит злоумышленник)
- Авторизация обходом: запрос превращается в проверку всех строк: "' OR '1'='1' --" (ядро проверки 1=11=11=1).
- UNION‑инъекция для вытягивания данных: "' UNION SELECT credit_card,1 FROM payments --" (ядро использования 111 как столбца).
- Разрушение/удаление: "'; DROP TABLE users; --" — если разрешены несколько команд.
- Blind SQL injection: побитовое/логическое угадывание данных через время/ошибки (например, payload типа "' AND IF(SUBSTRING(password,1,1)='a', SLEEP(5), 0) --").
- Использование кодировок/обхода фильтров: экранирование, комментарии, байтовые последовательности.
Последствия: утечка/изменение/удаление данных, обход авторизации, удалённое выполнение административных SQL‑команд.
Способы защиты (по приоритету)
1. Параметризованные запросы (prepared statements) — основной и обязательный способ.
- PDO:
$pdo = new PDO(..., [PDO::ATTR_EMULATE_PREPARES => false]);
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute([':name' => $_GET['name']]);
- mysqli:
$stmt = $mysqli->prepare("SELECT * FROM users WHERE name = ?");
$stmt->bind_param("s", $_GET['name']);
$stmt->execute();
Пояснение: параметры передаются отдельно от текста запроса, нельзя изменить структуру SQL.
2. Валидация и нормализация входа (white‑list):
- Для имён — разрешить только буквы, пробелы и максимум N символов: проверка по регулярному выражению, ограничение длины.
Пример: if (!preg_match('/^[\p{L}\- ]{1,100}$/u', $name)) { /* reject */ }
- Для числовых полей — явно приводить к числу: $id = (int)$_GET['id'].
Пояснение: whitelist над blacklist — надёжнее.
3. Экранирование (как вторичный метод):
- mysqli_real_escape_string — уменьшает риск, но не заменяет подготовленные выражения. Использовать только если параметризованные запросы невозможны.
4. Отключить возможность выполнения нескольких запросов в одном вызове:
- Не использовать mysqli_multi_query; в PDO по умолчанию многозапросы не выполняются.
5. Минимизация прав БД:
- Аккаунт приложения должен иметь только необходимые права (SELECT/INSERT/UPDATE и т. п.), не должен иметь DROP/DELETE без нужды.
6. Настройки PDO:
- Отключить эмуляцию подготовленных выражений: PDO::ATTR_EMULATE_PREPARES = false (чтобы реальные prepared statements использовались сервером).
7. Защита на уровне приложений и инфраструктуры:
- Логи и мониторинг подозрительных запросов.
- Web Application Firewall (WAF) как дополнительный барьер.
- Прячьте подробные сообщения об ошибках от пользователя.
Короткая демонстрация безопасного кода (PDO):
$pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_EMULATE_PREPARES => false]);
$name = $_GET['name']; // лучше пройти валидацию
$stmt = $pdo->prepare("SELECT id, name, email FROM users WHERE name = :name");
$stmt->execute([':name' => $name]);
$user = $stmt->fetch();
Резюме
- Самое важное: никогда не вставлять сырые данные в SQL — используйте подготовленные выражения + валидацию (whitelist и ограничение длины) + минимальные права у БД.