Безопасность PHP приложений: топ-10 уязвимостей на практике
PHP остаётся одним из самых популярных языков для веб-разработки, но его гибкость часто оборачивается серьёзными проблемами безопасности. По данным OWASP, 80% атак на веб-приложения связаны с уязвимостями, которые можно предотвратить на этапе написания кода. В этой статье мы разберём 10 самых распространённых уязвимостей PHP-приложений с реальными примерами кода и методами защиты. Материал будет полезен как начинающим, так и опытным разработчикам.
1. SQL-инъекции (SQL Injection)
Самая опасная и распространённая уязвимость. Атакующий вводит SQL-код через поля ввода, получая доступ к базе данных.
Уязвимый код:
$username = $_POST['username'];
$query = "SELECT * FROM users WHERE username = '$username'";
Атака: Ввод ' OR '1'='1 превращает запрос в SELECT * FROM users WHERE username = '' OR '1'='1', возвращая всех пользователей.
Защита: Используйте подготовленные запросы (prepared statements) с PDO:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(['username' => $_POST['username']]);
2. XSS (Cross-Site Scripting)
Атакующий внедряет JavaScript-код, который выполняется в браузере жертвы. Бывает трёх типов: reflected, stored и DOM-based.
Уязвимый код (stored XSS):
echo "<div>" . $comment . "</div>";
Защита: Экранируйте вывод с помощью htmlspecialchars():
echo "<div>" . htmlspecialchars($comment, ENT_QUOTES, 'UTF-8') . "</div>";
Для HTML-контента используйте библиотеки типа HTML Purifier.
3. CSRF (Cross-Site Request Forgery)
Атака заставляет авторизованного пользователя выполнить нежелательное действие на сайте, например, смену пароля или перевод средств.
Защита: Внедрите CSRF-токены:
// Генерация токена
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// В форме
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';
// Проверка
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die('CSRF-атака обнаружена');
}
4. Path Traversal (Обход каталогов)
Атакующий манипулирует путями к файлам, чтобы получить доступ к системным файлам (/etc/passwd и т.д.).
Уязвимый код:
$file = $_GET['file'];
include("pages/" . $file);
Защита: Используйте белые списки или функцию basename():
$allowed = ['home', 'about', 'contact'];
$file = basename($_GET['file']);
if (in_array($file, $allowed)) {
include("pages/$file.php");
} else {
die('Недопустимый файл');
}
5. File Upload Vulnerabilities (Уязвимости загрузки файлов)
Атакующий загружает PHP-скрипт вместо изображения, получая удалённый доступ к серверу.
Защита:
- Проверяйте MIME-тип файла:
$_FILES['file']['type'] - Используйте
finfoдля определения реального типа - Запрещайте выполнение скриптов в папке загрузок через
.htaccess - Генерируйте уникальные имена файлов:
md5(uniqid()) . '.jpg'
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
$allowed = ['image/jpeg', 'image/png'];
if (!in_array($mime, $allowed)) {
die('Недопустимый тип файла');
}
6. Session Fixation (Фиксация сессии)
Атакующий навязывает пользователю известный идентификатор сессии, чтобы перехватить её после авторизации.
Защита: После успешной аутентификации регенерируйте ID сессии:
session_regenerate_id(true);
Также установите параметры куки: session_set_cookie_params(['httponly' => true, 'secure' => true, 'samesite' => 'Strict']);
7. Command Injection (Внедрение команд)
Атакующий выполняет системные команды через уязвимые функции типа exec(), system() или shell_exec().
Уязвимый код:
$domain = $_GET['domain'];
echo shell_exec("ping -c 1 $domain");
Защита: Используйте escapeshellarg() или escapeshellcmd():
$domain = escapeshellarg($_GET['domain']);
echo shell_exec("ping -c 1 $domain");
8. Insecure Deserialization (Небезопасная десериализация)
PHP автоматически восстанавливает объекты из сериализованных данных, что может привести к удалённому выполнению кода.
Защита: Никогда не десериализуйте данные от пользователя. Используйте JSON вместо сериализации:
$data = json_decode($_POST['data'], true);
Если нужна сериализация — применяйте белые списки классов через unserialize() с callback-функцией.
9. Missing Authentication Checks (Отсутствие проверки аутентификации)
Разработчики часто забывают защитить административные страницы или API-эндпоинты.
Защита: Создайте middleware для проверки сессии:
function requireAuth() {
if (!isset($_SESSION['user_id'])) {