Кейс безопасности: в PHP-приложении есть форма входа, где пароль сравнивается с базой через прямой SQL без параметризации. Объясните риск и предложите три практических меры для устранения уязвимости.
Риск (кратко): прямое встраивание пароля/логина в SQL без параметризации делает форму входа уязвимой к SQL-инъекциям — злоумышленник может обойти аутентификацию, вытянуть/удалить данные, изменить привилегии или выполнить произвольные команды через базу данных. Практические меры (коротко и применимо): 111 Использовать подготовленные выражения (parameterized queries). Преимущество: значения пользователей не интерпретируются как часть SQL. Пример на PDO: ```php $stmt = $pdo->prepare('SELECT password_hash FROM users WHERE username = ?'); $stmt->execute([$username]); $hash = $stmt->fetchColumn(); if ($hash && password_verify($password, $hash)) { // успешный вход } ``` Не делайте: `"... WHERE username = '$username' AND password = '$password'"`. 222 Никогда не хранить пароли в открытом виде — хранить и проверять безопасные хеши. Используйте встроенные функции PHP: `password_hash()` при регистрации и `password_verify()` при входе. Пример: ```php // при регистрации $hash = password_hash($password, PASSWORD_DEFAULT); // при входе — сравниваем с хешем из БД (см. пункт 1) if (password_verify($password, $hash)) { ... } ``` Рекомендации: использовать `PASSWORD_DEFAULT` или `PASSWORD_ARGON2ID`, периодически проверять `password_needs_rehash()` и обновлять хешы. 333 Ограничения и защита по периметру (снизить ущерб при возможной уязвимости). Конкретно: - дать пользователю БД минимальные привилегии (только `SELECT`/`UPDATE` на нужные таблицы, без `DROP`/`CREATE`/`GRANT`). - ввести защиту от перебора: блокировка аккаунта или временная задержка после 555 неудачных попыток, rate-limiting по IP, CAPTCHА. - логировать попытки входа и настраивать оповещения о подозрительной активности; при возможности — добавить многофакторную аутентификацию (MFA). Короткие замечания: экранирование вручную менее надёжно, чем параметризация; комбинируйте меры 111 и 222 как обязательные, 333 — для снижения рисков и обнаружения атак.
Практические меры (коротко и применимо):
111 Использовать подготовленные выражения (parameterized queries).
Преимущество: значения пользователей не интерпретируются как часть SQL. Пример на PDO:
```php
$stmt = $pdo->prepare('SELECT password_hash FROM users WHERE username = ?');
$stmt->execute([$username]);
$hash = $stmt->fetchColumn();
if ($hash && password_verify($password, $hash)) {
// успешный вход
}
```
Не делайте: `"... WHERE username = '$username' AND password = '$password'"`.
222 Никогда не хранить пароли в открытом виде — хранить и проверять безопасные хеши.
Используйте встроенные функции PHP: `password_hash()` при регистрации и `password_verify()` при входе. Пример:
```php
// при регистрации
$hash = password_hash($password, PASSWORD_DEFAULT);
// при входе — сравниваем с хешем из БД (см. пункт 1)
if (password_verify($password, $hash)) { ... }
```
Рекомендации: использовать `PASSWORD_DEFAULT` или `PASSWORD_ARGON2ID`, периодически проверять `password_needs_rehash()` и обновлять хешы.
333 Ограничения и защита по периметру (снизить ущерб при возможной уязвимости). Конкретно:
- дать пользователю БД минимальные привилегии (только `SELECT`/`UPDATE` на нужные таблицы, без `DROP`/`CREATE`/`GRANT`).
- ввести защиту от перебора: блокировка аккаунта или временная задержка после 555 неудачных попыток, rate-limiting по IP, CAPTCHА.
- логировать попытки входа и настраивать оповещения о подозрительной активности; при возможности — добавить многофакторную аутентификацию (MFA).
Короткие замечания: экранирование вручную менее надёжно, чем параметризация; комбинируйте меры 111 и 222 как обязательные, 333 — для снижения рисков и обнаружения атак.