Найдите уязвимость и предложите исправление для этого PHP-кода: $q = "SELECT * FROM users WHERE name = '".$_GET['name']."'"; $r = mysqli_query($db, $q); — обсудите не только SQL-инъекции, но и вопросы валидации, минимизации прав, логирования и угрозы в контексте веб-приложений
Уязвимость - Прямая подстановка \$_GET['name'] в запрос создаёт SQL‑инъекцию: злоумышленник может подставить синтаксис SQL (например `' OR '1'='1`) и прочитать/изменить/удалить данные. Дополнительные проблемы - SELECT * выдаёт все поля (включая, возможно, хеши паролей) — избыточная утечка данных. - Нет валидации/нормализации ввода (длина, допустимые символы, кодировка). - Возможна переборная (enumeration) атака по имени — отсутствие rate‑limit/блокировок. - Ошибки БД могут выводиться пользователю — утечка служебной информации. - Используется привилегированный DB‑пользователь — излишние привилегии увеличивают риск. - Логирование: либо отсутствует, либо логируются сырые пользовательские данные (опасно). - Использование GET для действий, влияющих на состояние (если применимо) — CSRF/кеширование. Рекомендации по исправлению (кратко) 1. Использовать подготовленные выражения (prepared statements) с привязкой параметров — блокирует SQL‑инъекции. 2. Валидация входа по white‑list: допустимые символы, обрезка, ограничение длины (например, максимум 100100100 символов). 3. Ограничить возвращаемые столбцы — не использовать `SELECT *`, явно перечислять нужные поля. 4. Установить соединение в кодировке `utf8mb4` (mysqli_set_charset) — избежать проблем с кодировками. 5. Минимизация привилегий: DB‑пользователь приложения должен иметь только нужные права (например, только SELECT на конкретные столбцы/таблицу). 6. Не выводить детальные ошибки БД пользователю; логировать их в защищённое хранилище. 7. Логировать подозрительные запросы/ошибки, но не хранить в логах сырые пароли/секреты; применять rate limiting и мониторинг аномалий. 8. При отображении данных — экранировать/кодировать выход (предотвращать XSS). 9. Если операция изменяет состояние — не делать её через GET и защищать от CSRF. Пример исправленного кода (mysqli, подготовленное выражение, ограничение столбцов, валидация): $qName = isset($_GET['name']) ? trim($_GET['name']) : ''; // валидация: допустим только буквы, цифры, пробелы и некоторые знаки, длина 1..100 if (!preg_match('/^[\p{L}\p{N} .\'-]{1,100}$/u', $qName)) { error_log('Invalid name param from ' . $_SERVER['REMOTE_ADDR']); http_response_code(400); exit('Invalid input'); } mysqli_set_charset($db, 'utf8mb4'); // подготовленный запрос, явно перечислены столбцы; лимитируем результат $stmt = mysqli_prepare($db, "SELECT id, name, email FROM users WHERE name = ? LIMIT 1"); mysqli_stmt_bind_param($stmt, 's', $qName); mysqli_stmt_execute($stmt); $res = mysqli_stmt_get_result($stmt); if ($res) { $row = mysqli_fetch_assoc($res); // далее — безопасный вывод с экранированием } else { // логируем внутреннюю ошибку, не отдаём её пользователю error_log('DB error: ' . mysqli_error($db)); http_response_code(500); } Кратко по логированию и мониторингу - Логируйте неуспешные/аномальные параметры и частые попытки, но избегайте записи секретов. - Настройте оповещения при всплесках запросов/ошибок. - Храните логи защищённо и ограничьте доступ к ним. Минимизация прав (пример политики) - DB‑аккаунт приложения: только SELECT на таблицу users и только нужные столбцы; запрет DDL/DML, DROP, GRANT и т.п. Угрозы при сохранении текущего кода - Эксплуатация SQL‑инъекции → утечка всех записей, обход аутентификации, изменение данных, возможная эскалация (в зависимости от прав БД), data exfiltration, дальнейшее проникновение. Итог - Самое критичное: заменить конкатенацию на подготовленные выражения + валидация входа + минимизация прав + безопасное логирование и вывод. Это закроет основную уязвимость и снизит сопутствующие риски.
- Прямая подстановка \$_GET['name'] в запрос создаёт SQL‑инъекцию: злоумышленник может подставить синтаксис SQL (например `' OR '1'='1`) и прочитать/изменить/удалить данные.
Дополнительные проблемы
- SELECT * выдаёт все поля (включая, возможно, хеши паролей) — избыточная утечка данных.
- Нет валидации/нормализации ввода (длина, допустимые символы, кодировка).
- Возможна переборная (enumeration) атака по имени — отсутствие rate‑limit/блокировок.
- Ошибки БД могут выводиться пользователю — утечка служебной информации.
- Используется привилегированный DB‑пользователь — излишние привилегии увеличивают риск.
- Логирование: либо отсутствует, либо логируются сырые пользовательские данные (опасно).
- Использование GET для действий, влияющих на состояние (если применимо) — CSRF/кеширование.
Рекомендации по исправлению (кратко)
1. Использовать подготовленные выражения (prepared statements) с привязкой параметров — блокирует SQL‑инъекции.
2. Валидация входа по white‑list: допустимые символы, обрезка, ограничение длины (например, максимум 100100100 символов).
3. Ограничить возвращаемые столбцы — не использовать `SELECT *`, явно перечислять нужные поля.
4. Установить соединение в кодировке `utf8mb4` (mysqli_set_charset) — избежать проблем с кодировками.
5. Минимизация привилегий: DB‑пользователь приложения должен иметь только нужные права (например, только SELECT на конкретные столбцы/таблицу).
6. Не выводить детальные ошибки БД пользователю; логировать их в защищённое хранилище.
7. Логировать подозрительные запросы/ошибки, но не хранить в логах сырые пароли/секреты; применять rate limiting и мониторинг аномалий.
8. При отображении данных — экранировать/кодировать выход (предотвращать XSS).
9. Если операция изменяет состояние — не делать её через GET и защищать от CSRF.
Пример исправленного кода (mysqli, подготовленное выражение, ограничение столбцов, валидация):
$qName = isset($_GET['name']) ? trim($_GET['name']) : '';
// валидация: допустим только буквы, цифры, пробелы и некоторые знаки, длина 1..100
if (!preg_match('/^[\p{L}\p{N} .\'-]{1,100}$/u', $qName)) {
error_log('Invalid name param from ' . $_SERVER['REMOTE_ADDR']);
http_response_code(400);
exit('Invalid input');
}
mysqli_set_charset($db, 'utf8mb4');
// подготовленный запрос, явно перечислены столбцы; лимитируем результат
$stmt = mysqli_prepare($db, "SELECT id, name, email FROM users WHERE name = ? LIMIT 1");
mysqli_stmt_bind_param($stmt, 's', $qName);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
if ($res) {
$row = mysqli_fetch_assoc($res);
// далее — безопасный вывод с экранированием
} else {
// логируем внутреннюю ошибку, не отдаём её пользователю
error_log('DB error: ' . mysqli_error($db));
http_response_code(500);
}
Кратко по логированию и мониторингу
- Логируйте неуспешные/аномальные параметры и частые попытки, но избегайте записи секретов.
- Настройте оповещения при всплесках запросов/ошибок.
- Храните логи защищённо и ограничьте доступ к ним.
Минимизация прав (пример политики)
- DB‑аккаунт приложения: только SELECT на таблицу users и только нужные столбцы; запрет DDL/DML, DROP, GRANT и т.п.
Угрозы при сохранении текущего кода
- Эксплуатация SQL‑инъекции → утечка всех записей, обход аутентификации, изменение данных, возможная эскалация (в зависимости от прав БД), data exfiltration, дальнейшее проникновение.
Итог
- Самое критичное: заменить конкатенацию на подготовленные выражения + валидация входа + минимизация прав + безопасное логирование и вывод. Это закроет основную уязвимость и снизит сопутствующие риски.