Уязвимость: SQL‑инъекция — строковая конкатенация переменных в запросе: $query = "SELECT * FROM users WHERE login = '".$user."' AND pass = '".$pass."'"; Пример атаки и почему это работает - Если атакующий подставит, например, в поле логина payload типа ' OR '111'='111
то итоговый запрос станет что‑то вроде SELECT * FROM users WHERE login = '' OR '111'='111' AND pass = '...'; условие всегда истинно → обход аутентификации. - Возможности злоумышленника: обход авторизации, чтение/изменение/удаление данных, эксфильтрация через UNION, побочные/тайм‑базированные инъекции, выполнение нескольких запросов (если сервер позволяет), эскалация до RCE в некоторых конфигурациях. Последствия - Компрометация учётных записей (включая admin). - Утечка персональных данных, повреждение БД, репутационные/правовые/финансовые потери. Как исправить (конкретный безопасный паттерн) 1) Использовать подготовленные выражения (prepared statements) + хранить пароли хешированными: PHP (mysqli, пример): ```php // установить кодировку и подключение $db->set_charset('utf8mb4'); // подготовленный запрос: параметризированный по login $stmt = $db->prepare("SELECT id, pass_hash FROM users WHERE login = ?"); $stmt->bind_param("s", $login); $stmt->execute(); $stmt->bind_result($id, $pass_hash); if ($stmt->fetch()) { if (password_verify($password, $pass_hash)) { // успех: авторизовать пользователя } else { // неверный пароль } } else { // пользователь не найден } $stmt->close(); ``` При регистрации: `password_hash($password, PASSWORD_DEFAULT)` — хранить только хеш. 2) Валидация и ограничение входных данных - Белые списки/форматы (регулярные выражения) для логинов, длина, кодировка. - Ограничивать длину входа, избегать передачи больших входных данных в SQL. 3) Минимизация привилегий - Под веб‑приложение использовать отдельного БД‑пользователя с минимальными правами (обычно SELECT/INSERT/UPDATE/DELETE только для нужных таблиц). - Не давать права DROP, GRANT, ADMIN и т.п. Дополнительные рекомендации - Отключить emulated prepared statements в PDO (если используете PDO) и всегда использовать реальные параметризованные запросы. - Использовать TLS для соединения к БД и для веб‑трафика (HTTPS). - Не выводить сырые сообщения об ошибках пользователю; логировать ошибки безопасно. - Ограничивать количество попыток входа / вводить капчу, rate limiting, блокировки аккаунтов при попытках. - Регулярный аудит запросов, WAF как дополнительная защита. - По возможности минимизировать возвращаемые столбцы (SELECT id, login — вместо SELECT *). Кратко: замените конкатенацию на prepared statements, храните пароли как хеши (password_hash/verify), валидируйте вход, дайте БД‑пользователю минимальные привилегии и соблюдайте прочие практики безопасности.
$query = "SELECT * FROM users WHERE login = '".$user."' AND pass = '".$pass."'";
Пример атаки и почему это работает
- Если атакующий подставит, например, в поле логина payload типа
' OR '111'='111 то итоговый запрос станет что‑то вроде
SELECT * FROM users WHERE login = '' OR '111'='111' AND pass = '...';
условие всегда истинно → обход аутентификации.
- Возможности злоумышленника: обход авторизации, чтение/изменение/удаление данных, эксфильтрация через UNION, побочные/тайм‑базированные инъекции, выполнение нескольких запросов (если сервер позволяет), эскалация до RCE в некоторых конфигурациях.
Последствия
- Компрометация учётных записей (включая admin).
- Утечка персональных данных, повреждение БД, репутационные/правовые/финансовые потери.
Как исправить (конкретный безопасный паттерн)
1) Использовать подготовленные выражения (prepared statements) + хранить пароли хешированными:
PHP (mysqli, пример):
```php
// установить кодировку и подключение
$db->set_charset('utf8mb4');
// подготовленный запрос: параметризированный по login
$stmt = $db->prepare("SELECT id, pass_hash FROM users WHERE login = ?");
$stmt->bind_param("s", $login);
$stmt->execute();
$stmt->bind_result($id, $pass_hash);
if ($stmt->fetch()) {
if (password_verify($password, $pass_hash)) {
// успех: авторизовать пользователя
} else {
// неверный пароль
}
} else {
// пользователь не найден
}
$stmt->close();
```
При регистрации: `password_hash($password, PASSWORD_DEFAULT)` — хранить только хеш.
2) Валидация и ограничение входных данных
- Белые списки/форматы (регулярные выражения) для логинов, длина, кодировка.
- Ограничивать длину входа, избегать передачи больших входных данных в SQL.
3) Минимизация привилегий
- Под веб‑приложение использовать отдельного БД‑пользователя с минимальными правами (обычно SELECT/INSERT/UPDATE/DELETE только для нужных таблиц).
- Не давать права DROP, GRANT, ADMIN и т.п.
Дополнительные рекомендации
- Отключить emulated prepared statements в PDO (если используете PDO) и всегда использовать реальные параметризованные запросы.
- Использовать TLS для соединения к БД и для веб‑трафика (HTTPS).
- Не выводить сырые сообщения об ошибках пользователю; логировать ошибки безопасно.
- Ограничивать количество попыток входа / вводить капчу, rate limiting, блокировки аккаунтов при попытках.
- Регулярный аудит запросов, WAF как дополнительная защита.
- По возможности минимизировать возвращаемые столбцы (SELECT id, login — вместо SELECT *).
Кратко: замените конкатенацию на prepared statements, храните пароли как хеши (password_hash/verify), валидируйте вход, дайте БД‑пользователю минимальные привилегии и соблюдайте прочие практики безопасности.