Что такое CSRF-атака и как от неё защититься?

«Что такое CSRF-атака и как от неё защититься?» — вопрос из категории Безопасность, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

CSRF (Cross-Site Request Forgery) — это вид атаки на веб-приложения, при которой злоумышленник заставляет браузер авторизованного пользователя выполнить нежелательный запрос к доверенному сайту. Атака возможна, потому что браузер автоматически отправляет cookies (включая сессионные) при каждом запросе к домену.

Сценарий атаки:

  1. Пользователь авторизуется на сайте bank.com. Его сессия сохраняется в cookie.
  2. Пользователь переходит на вредоносный сайт, который содержит скрытую форму или отправляет AJAX-запрос на bank.com/transfer?to=attacker&amount=1000.
  3. Браузер автоматически прикрепляет cookies сессии к этому запросу.
  4. Сервер bank.com видит валидную сессию и выполняет перевод.

Основной метод защиты — CSRF-токены: Сервер генерирует уникальный, секретный токен для каждой пользовательской сессии и внедряет его в формы (как скрытое поле) или в заголовки AJAX-запросов. При получении запроса на изменение состояния сервер проверяет соответствие токена из запроса токену в сессии.

Пример реализации защиты на PHP:

// 1. Генерация и сохранение токена в сессии при её старте
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// 2. Внедрение токена в HTML-форму
<form action="/transfer.php" method="POST">
    <input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($_SESSION['csrf_token'], ENT_QUOTES); ?>">
    <!-- остальные поля формы -->
</form>

// 3. Проверка токена при обработке POST-запроса
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
        http_response_code(403);
        die('Invalid CSRF token.');
    }
    // Токен верный, обрабатываем запрос
}

Важные моменты:

  • Используйте криптографически безопасные генераторы (random_bytes()).
  • Проверяйте с помощью hash_equals() для защиты от атак по времени.
  • В современных фреймворках (Laravel, Symfony, Django, Spring Security) защита от CSRF встроена и включается по умолчанию.