CSRF protection

Backbone.js является легковесным MVC-фреймворком для JavaScript, ориентированным на организацию клиентской логики веб-приложений. Несмотря на то, что Backbone не предоставляет встроенных средств для защиты от CSRF (Cross-Site Request Forgery), интеграция механизма CSRF-защиты в приложения на Backbone.js — ключевой элемент безопасного взаимодействия с сервером.

Механизм CSRF

CSRF-атака направлена на выполнение нежелательных действий от имени аутентифицированного пользователя на доверенном сайте. На практике это часто выражается в несанкционированных запросах на изменение данных, отправляемых браузером пользователя без его ведома. Для защиты серверы используют CSRF-токены — уникальные значения, связанные с пользовательской сессией, которые должны передаваться с каждым изменяющим запросом.

Использование CSRF-токена в Backbone.js

Backbone.js использует Backbone.sync для всех операций с сервером (create, read, update, delete). Этот метод является центральной точкой для внедрения CSRF-токена в AJAX-запросы.

Переопределение Backbone.sync

Для автоматической отправки CSRF-токена можно переопределить Backbone.sync:

// Получение CSRF-токена из мета-тега HTML
function getCSRFToken() {
    var meta = document.querySelector('meta[name="csrf-token"]');
    return meta ? meta.getAttribute('content') : '';
}

// Сохранение оригинальной функции sync
var originalSync = Backbone.sync;

// Переопределение Backbone.sync
Backbone.sync = function(method, model, options) {
    options = options || {};

    // Инициализация заголовков, если они не заданы
    options.headers = options.headers || {};
    options.headers['X-CSRF-Token'] = getCSRFToken();

    return originalSync.call(this, method, model, options);
};

В этом примере каждый запрос create, update, delete будет автоматически включать CSRF-токен в заголовки.

Интеграция с сервером

На серверной стороне CSRF-токен должен проверяться для всех запросов, которые изменяют состояние (POST, PUT, DELETE). Токен обычно передается в заголовке X-CSRF-Token или как часть тела запроса. Пример для Express.js:

const csrf = require('csurf');
const cookieParser = require('cookie-parser');

app.use(cookieParser());
app.use(csrf({ cookie: true }));

app.post('/update', (req, res) => {
    res.send('Данные обновлены');
});

Backbone.js в сочетании с CSRF-токенами гарантирует, что все изменения данных на сервере происходят только при наличии валидного токена.

CSRF-токен в моделях и коллекциях

Можно автоматически включать CSRF-токен в методы моделей:

var Item = Backbone.Model.extend({
    urlRoot: '/items',
    sync: function(method, model, options) {
        options = options || {};
        options.headers = options.headers || {};
        options.headers['X-CSRF-Token'] = getCSRFToken();
        return Backbone.sync(method, model, options);
    }
});

Для коллекций аналогично:

var ItemCollection = Backbone.Collection.extend({
    model: Item,
    url: '/items',
    sync: function(method, collection, options) {
        options = options || {};
        options.headers = options.headers || {};
        options.headers['X-CSRF-Token'] = getCSRFToken();
        return Backbone.sync(method, collection, options);
    }
});

Учет специфик кэширования

Браузеры иногда кэшируют GET-запросы, что может привести к непреднамеренному выполнению старых CSRF-запросов. Для предотвращения этого рекомендуется:

  • Использовать cache: false в AJAX-запросах.
  • Добавлять уникальные параметры запроса (_timestamp).
  • Ограничивать методами изменения состояния только POST, PUT, DELETE.

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

  • Всегда хранить CSRF-токен в безопасном месте (мета-тег, cookie с HttpOnly=false для JS-доступа).
  • Не отправлять CSRF-токен для GET-запросов.
  • Переопределять Backbone.sync глобально для обеспечения единообразия.
  • Тестировать защиту с использованием инструментов наподобие Postman для проверки отказа неавторизованных запросов.

Заключение на практике

Корректная интеграция CSRF-защиты в Backbone.js снижает риск атак, связанных с поддельными запросами. Переопределение Backbone.sync и включение токена в заголовки или тело запросов позволяет централизованно управлять безопасностью, минимизируя дублирование кода и ошибки в отдельных моделях или коллекциях.