Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

Сервер

Добавить промежуточное ПО 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'));

Ответ 2

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. Пока токен находится в запросе (заголовок, тело или запрос), вы хороши. Это почти все, что есть.

Ответ 3

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

Например:

index.html (с помощью Handlebars для templating...)

<!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.

Ответ 4

В сервере:

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);
});

Ответ 5

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.