Топ-10 уязвимостей PHP приложений: как защитить свой код
PHP остается одним из самых популярных языков для веб-разработки. Однако его гибкость и простота часто приводят к появлению критических уязвимостей. По статистике OWASP, более 70% веб-приложений имеют хотя бы одну серьезную брешь в безопасности. В этой статье мы разберем 10 наиболее распространенных уязвимостей PHP-приложений, покажем примеры опасного кода и дадим практические рекомендации по защите.
1. SQL-инъекции (SQL Injection)
Самая известная и опасная атака. Злоумышленник внедряет SQL-код через пользовательский ввод.
Опасный код:
<?php
$id = $_GET['id'];
$query = "SELECT * FROM users WHERE id = $id";
$result = mysqli_query($conn, $query);
?>
Безопасный код (использование подготовленных запросов):
<?php
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
?>
Рекомендации:
- Всегда используйте подготовленные выражения (PDO или MySQLi).
- Никогда не конкатенируйте пользовательские данные в SQL-запросы.
- Валидируйте типы данных (например,
is_numeric()для ID).
2. XSS (Cross-Site Scripting)
Внедрение JavaScript-кода на страницу через непроверенные данные. Кража кук, перенаправление на фишинг-сайты.
Опасный код:
<?php
echo "Привет, " . $_GET['name'];
?>
Безопасный код:
<?php
echo "Привет, " . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
?>
Рекомендации:
- Экранируйте вывод с помощью
htmlspecialchars(). - Установите Content-Security-Policy (CSP) в заголовках.
- Для JSON-ответов используйте
json_encode().
3. CSRF (Cross-Site Request Forgery)
Злоумышленник заставляет авторизованного пользователя выполнить нежелательное действие (например, перевод денег).
Пример формы без защиты:
<form action="delete.php" method="POST">
<input type="hidden" name="id" value="123">
<input type="submit" value="Удалить">
</form>
Безопасный код (с токеном):
<?php
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
?>
<form action="delete.php" method="POST">
<input type="hidden" name="token" value="<?= $_SESSION['token'] ?>">
<input type="hidden" name="id" value="123">
<input type="submit" value="Удалить">
</form>
Рекомендации:
- Генерируйте уникальные CSRF-токены для каждой формы.
- Проверяйте токены на сервере перед выполнением действий.
- Используйте SameSite Cookie (Lax или Strict).
4. Некорректная аутентификация и управление сессиями
Слабая защита сессий, утечка идентификаторов, фиксация сессии.
Уязвимый код:
<?php
session_start();
if ($_POST['password'] == 'admin123') {
$_SESSION['logged'] = true;
}
?>
Безопасный код:
<?php
session_start();
session_regenerate_id(true); // Смена ID сессии после логина
// Хеширование пароля
$hash = password_hash($_POST['password'], PASSWORD_BCRYPT);
if (password_verify($input_password, $hash)) {
$_SESSION['logged'] = true;
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
}
?>
Рекомендации:
- Используйте
password_hash()иpassword_verify(). - Регенерируйте ID сессии при смене уровня доступа.
- Устанавливайте короткое время жизни сессии (например, 30 минут).
- Храните сессии в базе данных или Redis, а не в файлах.
5. Insecure Direct Object References (IDOR)
Доступ к чужим данным через подмену ID в URL или параметрах.
Опасный код:
<?php
$invoice = $db->query("SELECT * FROM invoices WHERE id = " . $_GET['id']);
// Нет проверки принадлежности пользователю
?>
Безопасный код:
<?php
$stmt = $db->prepare("SELECT * FROM invoices WHERE id = ? AND user_id = ?");
$stmt->execute([$_GET['id'], $_SESSION['user_id']]);
$invoice = $stmt->fetch();
if (!$invoice) {
http_response_code(403);
die("Доступ запрещен");
}
?>
Рекомендации:
- Всегда проверяйте права доступа на уровне запроса.
- Используйте UUID вместо автоинкрементных ID.
- Не передавайте ID в URL, если объект принадлежит текущему пользователю.
6. Загрузка вредоносных файлов
Пользователь загружает PHP-скрипт под видом картинки.
Уязвимый код:
<?php
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
?>
Безопасный код:
<?php