Как реализовать защиту CSRF в вызовах Ajax с использованием express.js (ищите полный пример)?

Я пытаюсь реализовать защиту CSRF в приложении, созданном с использованием node.js с использованием инфраструктуры express.js. Приложение широко использует почтовые звонки Ajax на сервер. Я понимаю, что инфраструктура подключения предоставляет промежуточное программное обеспечение CSRF, но я не уверена, как реализовать его в рамках клиентских запросов Ajax.

Об этом есть кусочки в других Вопросах, размещенных здесь в stackoverflow, но мне еще предстоит найти достаточно полный пример того, как реализовать это как на стороне клиента, так и на стороне сервера.

У кого-нибудь есть рабочий пример, которым они хотят поделиться, как реализовать это? Большинство примеров, которые я видел, предполагают, что вы визуализируете форму на стороне сервера и затем отправляете ее (вместе со встроенным полем формы csrf_token) на сторону клиента. В моем приложении весь контент отображается на стороне клиента (включая шаблоны) через Backbone.js. Все, что делает сервер - это предоставляет значения в формате JSON, которые используются различными моделями в Backbone.js на стороне клиента. Насколько я понимаю, мне нужно было бы извлечь csrf_token через ajax, прежде чем его можно будет использовать. Однако я обеспокоен тем, что это может быть проблематично с точки зрения безопасности. Это действительная проблема?

Ответы на вопрос(5)

server.js

...
// All Cookies/Sessions/BodyParser go first
app.use(express.csrf());
...
// Get the request
app.post('/ajax', function(req, res){
    res.render('somelayout', {csrf_token: req.session._csrf});
});

В somelayout.jade

input(type='hidden', name='_csrf', value=csrf_token)

Промежуточное программное обеспечение CSRF генерирует токен csrf только один раз за сеанс, поэтому он, вероятно, не изменится в течение посещения пользователя.

Кроме того, он не проверяет токен в запросах GET и HEAD. Пока токен находится в запросе (заголовок, тело или запрос), у вас все хорошо. Это почти все, что нужно сделать.

 26 июн. 2012 г., 07:06
Если вы можете, хороший способ передать CSRF клиенту - это сделать его внутриmeta тег (а-ля Rails) или нечто подобное от Express.
 Benjen26 июн. 2012 г., 05:24
Спасибо за быстрый ответ. В моем приложении весь контент на стороне клиента выполняется через ajax. Актуальный рендеринг контента (включая шаблоны) выполняется на стороне клиента. Все, что делает сервер - это предоставляет переменные данные на стороне клиента в формате JSON. Это означало бы, что мне нужно получить токен CSRF через ajax, чтобы отобразить его на странице, чтобы затем можно было отправить его обратно в запрос поста ajax. Я обеспокоен тем, что это может быть проблематично с точки зрения безопасности, действительно ли это вызывает озабоченность?

Это можно сделать, добавивmeta тег для токена CSRF, а затем передавать токен CSRF при каждом запросе Ajax

Server

Добавить промежуточное программное обеспечение CSRF

app.use(express.csrf());
app.use(function (req, res, next) {
  res.locals.token = req.session._csrf;
  next();
});

Вы можете передать токен CSRF на сторону клиента через, скажем, метатег. Например, вJade

meta(name="csrf-token", content="#{token}")
Client

В jQuery есть функция ajaxPrefilter, которая позволяет вам предоставлять обратный вызов, который будет вызываться при каждом запросе Ajax. Затем установите заголовок, используя ajaxPrefilter.

var CSRF_HEADER = 'X-CSRF-Token';

var setCSRFToken = function (securityToken) {
  jQuery.ajaxPrefilter(function (options, _, xhr) {
    if (!xhr.crossDomain) {
      xhr.setRequestHeader(CSRF_HEADER, securityToken);
    }
  });
};

setCSRFToken($('meta[name="csrf-token"]').attr('content'));
 06 мар. 2017 г., 11:16
Как мы можем проверить этот токен на стороне сервера?
 26 окт. 2018 г., 05:45
@ Я согласен. Аскер запрашивает решение для рендеринга на стороне клиента, а на стороне сервера - только успокоительный API.
 27 авг. 2013 г., 07:04
наверное, лучший ответ здесь
 08 янв. 2015 г., 08:40
это должен быть принят ответ
 11 янв. 2015 г., 21:20
Я не согласен. Это хороший ответ, но он не решает проблему отсутствия рендеринга на стороне сервера. В нем упоминается использование Jade для визуализации мета-тега на странице. Но это значение тега должно быть сгенерировано на стороне сервера, и поскольку первоначальный запросчик говорит, что ни одно из его представлений не генерируется на стороне сервера, это не сработает.

На сервере:

app.use(function (req, res) {
  res.locals._csrf = req.csrfToken();
  res.locals.csrf_form_html = '<input type="hidden" name="_csrf" value="' + req.csrfToken() + '" >';
  req.next();
});

В клиенте: (шаблон swig)

var csrf = {{ _csrf|json|safe }};

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': csrf
  }
});

$.post("/create", data, function(result) {
  console.log(result);
}).fail(function(){
  console.log(arguments);
});
 06 мар. 2017 г., 11:20
Как вы проверяете токен на стороне сервера?

1. Добавьте промежуточное ПО защиты csrf:

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

// csrf middleware
app.use(function (req, res, next) {
   res.cookie('X-CSRF-Token', req.csrfToken());
   // this line below is for using csrfToken value in normal forms (as a hidden input)
   res.locals.csrfToken = req.csrfToken(); 
   next();
});

// routing setup goes here

2. ДобавитьbeforeSend обратный вызов с использованием$.ajaxSetup: (добавь это куда-нибудь до всех ваших вызовов ajax)

$.ajaxSetup({
beforeSend: function (xhr, settings) {
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
        // Only send the token to relative URLs i.e. locally.
        xhr.setRequestHeader("X-CSRF-Token", getCookie('X-CSRF-Token'));
    }
}
});

3. Вот и все! теперь вы можете отправлять ajax-запросы, и вам не нужно добавлять что-либо в заголовки или в качестве параметра запроса для прохождения через csrf.

Поскольку вы используетеBackbone.js для вашего приложения, я предполагаю, что это SPA, и вы изначально загружаетеindex.html файл, а затем сделать любые другие запросы сделаны черезajax звонки. Если это так, вы можете добавить небольшой фрагмент кода JS к вашемуindex.html файл для хранения токена crsf на будущееajax звонки.

Например:

index.html (используя Handlebars для шаблонов ...)

<!DOCTYPE html>
<html>
    <head>
        ...
        <script type="text/javascript">
            $( function() {
                window.Backbone.csrf = "{{csrfToken}}";
            });
        </script>
    </head>
    <body>
        ...
    </body>
</html>

Когда вы рендеритеindex.html файл, дайте емуcsrf маркер, что сгенерированный здесь фреймворк:req.session._csrf

Когда вы используетеBackbone.jsон устанавливает глобальную переменнуюBackbone, Все, что делает предыдущая функция, это устанавливает свойство с именемcsrf к глобальномуBackbone объект. И когда вы делаетеajax позвонитьPOST данные, просто добавьтеBackbone.csrf переменная к данным как_csrf который отправляется черезajax вызов.

Ваш ответ на вопрос