Защита от CSRF

Библиотека Cash, популярная среди разработчиков JavaScript, предоставляет удобный набор инструментов для работы с DOM, AJAX и событиями. Одной из критически важных задач при разработке веб-приложений является защита от Cross-Site Request Forgery (CSRF). CSRF-атаки возникают, когда злоумышленник заставляет браузер пользователя выполнить нежелательные действия на доверенном сайте, используя активную сессию пользователя. Cash не предоставляет встроенного механизма CSRF, но позволяет эффективно реализовать защиту с помощью AJAX и управления токенами.


Генерация и хранение CSRF-токена

CSRF-токен должен генерироваться на сервере и быть уникальным для каждой сессии или запроса. На клиентской стороне токен обычно хранится в:

  • HTML-атрибуте meta:
<meta name="csrf-token" content="токен_из_сессии">
  • Cookie (при использовании SameSite-флага для ограничения межсайтовых запросов):
Set-Cookie: csrf_token=токен_из_сессии; SameSite=Strict; HttpOnly

Cash позволяет удобно получать значения токенов из DOM:

const csrfToken = cash('meta[name="csrf-token"]').attr('content');

Вставка токена в AJAX-запросы

CSRF-токен необходимо включать во все изменяющие данные запросы (POST, PUT, PATCH, DELETE). Cash предоставляет метод ajax(), который легко расширяется для добавления заголовков:

cash.ajax({
    url: '/api/update-profile',
    method: 'POST',
    data: {
        username: 'new_user',
        email: 'user@example.com'
    },
    headers: {
        'X-CSRF-Token': csrfToken
    },
    success(response) {
        console.log('Профиль обновлён', response);
    },
    error(err) {
        console.error('Ошибка при обновлении', err);
    }
});

Ключевой момент: сервер должен проверять заголовок X-CSRF-Token и отклонять запросы с отсутствующим или некорректным токеном.


Автоматическое включение токена во все запросы

Для больших приложений удобно настроить Cash так, чтобы CSRF-токен автоматически добавлялся ко всем AJAX-запросам:

cash.ajaxSetup({
    headers: {
        'X-CSRF-Token': csrfToken
    }
});

После этого каждый вызов cash.ajax() будет автоматически содержать токен, что минимизирует риск ошибок при ручной вставке.


Защита форм

CSRF-атаки часто направлены на HTML-формы. Токен можно вставлять в скрытое поле формы:

<form id="updateForm" method="POST">
    <input type="hidden" name="csrf_token" value="">
    <input type="text" name="username">
    <button type="submit">Сохранить</button>
</form>

В Cash это делается динамически:

cash('#updateForm input[name="csrf_token"]').val(csrfToken);

При отправке формы с помощью AJAX поле csrf_token будет автоматически отправлено вместе с данными.


Обновление токена при истечении сессии

Некоторые серверные реализации генерируют новый CSRF-токен при каждом успешном запросе или после истечения сессии. В таких случаях важно обновлять токен на клиенте:

function updateCsrfToken(newToken) {
    cash('meta[name="csrf-token"]').attr('content', newToken);
}

После обновления токена можно пересоздать заголовки AJAX:

cash.ajaxSetup({
    headers: {
        'X-CSRF-Token': cash('meta[name="csrf-token"]').attr('content')
    }
});

Работа с CORS и безопасные заголовки

При кросс-доменных запросах CSRF-токены также должны быть проверены. Сервер должен разрешать только безопасные методы и включать заголовки:

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-CSRF-Token

Cash корректно отправляет пользовательские заголовки, включая X-CSRF-Token, если конфигурация CORS на сервере позволяет это.


Практические рекомендации

  1. Всегда использовать CSRF-токен для всех запросов, изменяющих данные.
  2. Хранить токен в защищённом месте: meta-тег или cookie с флагом HttpOnly/SameSite.
  3. Обновлять токен при изменении сессии или после успешной отправки данных.
  4. Использовать ajaxSetup для глобальной настройки заголовков и минимизации ошибок.
  5. Проверять CSRF-токен на сервере и отклонять любые подозрительные запросы.

Пример комплексной реализации

const csrfToken = cash('meta[name="csrf-token"]').attr('content');

cash.ajaxSetup({
    headers: {
        'X-CSRF-Token': csrfToken
    }
});

cash('#updateForm').on('submit', function(e) {
    e.preventDefault();
    cash.ajax({
        url: '/api/update-profile',
        method: 'POST',
        data: cash(this).serialize(),
        success(response) {
            if (response.newCsrfToken) {
                cash('meta[name="csrf-token"]').attr('content', response.newCsrfToken);
                cash.ajaxSetup({ headers: { 'X-CSRF-Token': response.newCsrfToken } });
            }
            console.log('Данные обновлены');
        },
        error(err) {
            console.error('Ошибка обновления', err);
        }
    });
});

Эта схема объединяет защиту форм, автоматическую настройку AJAX-заголовков и обновление токена при каждом успешном запросе, создавая надежный барьер против CSRF-атак.