Безопасность PHP приложений: топ-10 уязвимостей и защита

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Топ-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                

Блоги

Рекомендаций по книгам