Безопасность PHP приложений: топ-10 уязвимостей для начинающих
PHP остается одним из самых популярных языков для веб-разработки, но его гибкость часто оборачивается уязвимостями, если не соблюдать базовые правила безопасности. По данным OWASP, большинство взломов происходят из-за 10 типичных ошибок, которые допускают начинающие разработчики. В этой статье мы разберем каждую уязвимость с реальными примерами кода и покажем, как защитить ваше приложение.
1. SQL-инъекции (SQL Injection)
Самая распространенная атака. Злоумышленник внедряет вредоносный SQL-код через пользовательский ввод.
Уязвимый код:
<?php
$id = $_GET['id'];
$query = "SELECT * FROM users WHERE id = $id";
$result = mysqli_query($conn, $query);
?>
Защита: Используйте подготовленные запросы (prepared statements):
<?php
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
?>
2. XSS (Cross-Site Scripting)
Внедрение JavaScript-кода на страницу через непроверенные данные.
Уязвимый код:
<?php
echo "Привет, " . $_GET['name'];
?>
Защита: Экранируйте вывод через htmlspecialchars():
<?php
echo "Привет, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
?>
3. CSRF (Cross-Site Request Forgery)
Атака, при которой пользователь выполняет нежелательные действия от своего имени.
Уязвимый код:
<form action="/delete.php" method="POST">
<input type="submit" value="Удалить аккаунт">
</form>
Защита: Добавьте CSRF-токен:
<?php
session_start();
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
?>
<form action="/delete.php" method="POST">
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
<input type="submit" value="Удалить аккаунт">
</form>
4. Небезопасное хранение паролей
Хранение паролей в открытом виде или с устаревшими хешами (MD5, SHA1).
Уязвимый код:
<?php
$password = md5($_POST['password']);
// или
$password = sha1($_POST['password']);
?>
Защита: Используйте password_hash() и password_verify():
<?php
$hash = password_hash($_POST['password'], PASSWORD_BCRYPT);
// Проверка:
if (password_verify($input_password, $hash)) {
echo "Пароль верный";
}
?>
5. Небезопасная работа с файлами (Local/Remote File Inclusion)
Включение файлов через пользовательский ввод без проверки.
Уязвимый код:
<?php
include($_GET['page'] . '.php');
?>
Защита: Используйте белый список разрешенных файлов:
<?php
$allowed_pages = ['home', 'about', 'contact'];
$page = $_GET['page'] ?? 'home';
if (in_array($page, $allowed_pages)) {
include($page . '.php');
} else {
include('404.php');
}
?>
6. Неверная настройка сессий
Использование предсказуемых идентификаторов сессий или отсутствие регенерации.
Уязвимый код:
<?php
session_start();
$_SESSION['user_id'] = $user_id;
// Сессия не регенерируется после входа
?>
Защита:
<?php
session_start();
session_regenerate_id(true); // Регенерация ID после логина
$_SESSION['user_id'] = $user_id;
?>
7. Недостаточная валидация ввода
Доверие к любым данным от пользователя.
Уязвимый код:
<?php
$email = $_POST['email'];
mail($email, "Тема", "Сообщение");
?>
Защита: Валидируйте и фильтруйте ввод:
<?php
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if ($email) {
mail($email, "Тема", "Сообщение");
} else {
echo "Некорректный email";
}
?>
8. Небезопасное использование unserialize()
Десериализация данных из ненадежных источников может привести к RCE (Remote Code Execution).
Уязвимый код:
<?php
$data = unserialize($_GET['data']);
?>
Защита: Никогда не десериализуйте данные от пользователя. Используйте JSON:
<?php
$data = json_decode($_GET['data'], true);
?>
9. Утечка информации через ошибки
Вывод подробных сообщений об ошибках в production-среде.
Уязвимый код (php.ini):
display_errors = On
error_reporting = E_ALL
Защита: Настройте логирование вместо вывода ошибок:
display_errors = Off
error_reporting = E_ALL
log_errors = On
error_log = /var/log/php_errors.log
10. Отсутствие HTTPS и HSTS
Передача данных по незащищенному