2014-02-10 15 views
2

Поддержка предотвращения CSRF в приложении django отправляет токены CSRF на клиента через куки-файл и принимает токены CSRF от клиента либо в заголовке (X-CSRFToken), либо в файле cookie. Это отлично подходит для веб-приложений, отличных от CORS, без AJAX. Но, похоже, он не работает, если вы a) имеете одностраничное веб-приложение, которое общается с сервером через AJAX, и б) одностраничный webapp размещен в другом домене, чем сервер (CORS).CORS, Ajax и CSRF

Проблема в том, что одностраничный webapp (from domain1) не может читать файлы cookie домена домена (domain2), используя xhr.getResponseHeader или getCookie из-за ограничений CORS. Как веб-приложение javascript может отправить соответствующий токен CSRF на сервер, учитывая, что он не может читать файлы cookie?

xhr.getResponseHeader api ограничен извлечением заголовков Set-Cookie или Set-Cookie2 (по спецификации), и различные браузеры, поддерживающие CORS, как представляется, применяют это ограничение. Аналогично, функция getCookie JS будет читать все cookie, отличные от httpOnly, в домене webapp (domain1), но не будет читать те, которые установлены сервером в его домене (domain2).

Это не проблема в случаях, отличных от CORS, но в нашем приложении мы хотим разместить API в другом домене, чем клиентский webapp. Какие-либо предложения?

+0

Вы когда-нибудь это разрешили? Похоже, у тебя такая же проблема. – gcdev

+0

Нет, никогда не было разрешено. – eswenson

+0

Grr. ОК. Благодарю. – gcdev

ответ

0

Я работал над одним и тем же днем, и это сводило меня с ума. Я использую MVC WEB API, но есть похожие вещи, которые, я думаю, останавливают вас.

Моя проблема заключалась в том, что вызов OPTIONS на сервер, чтобы проверить, разрешает ли сервер отправлять настраиваемый заголовок, невозможен, поэтому фактический вызов GET/POST никогда не выполняется. Вы должны перезаписать запрос параметров на сервере, чтобы это разрешить. И, конечно же, разрешите orgin с сайта, с которого вы звоните на сервер.

Вот статья об этом в ASP.NET, но я думаю, что это поможет вам понять проблему, даже несмотря на то, что она является ASP.NET.

http://www.jefclaes.be/2012/09/supporting-options-verb-in-aspnet-web.html

Надеется, что это помогает.

+0

Спасибо. Тем не менее, я считаю, что проблемы, с которыми я сталкиваюсь, не связаны. Мой сервер django уже обрабатывает запросы OPTIONS, и веб-приложение получает эти ответы OPTIONS.Сервер предоставляет весь набор заголовков Access-Control-XXX. Единственное, что мы не можем получить, это поддержка токенов CSRF, потому что мы не можем читать cookie «csrftoken» из Javascript. – eswenson

+0

Если вам нужно прочитать или установить файлы cookie из браузера, вы можете использовать куки jQuery. https://github.com/carhartl/jquery-cookie – Gumbo

+0

Вы уверены, что cookie jQuery может получить файлы cookie в кросс-доменном чехле? – eswenson

0

Я думаю, что испытываю ту же проблему и разрешаю ее с помощью комбинации серверной части и клиентской стороны. Серверный (Django-Python):

origin = request.META.get('HTTP_ORIGIN', None) 
if origin and origin in settings.safe_origins: 
    response['Access-Control-Allow-Origin'] = origin 
    response['Access-Control-Allow-Credentials'] = 'true' 
    response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS' 
    response['Access-Control-Allow-Headers'] = request.META.get('Access-Control-Allow-Headers', 'x-requested-with, X-CSRFToken',) 
    response['Access-Control-Max-Age'] = 15 
    response['Allow'] = 'GET, POST, PUT, DELETE, OPTIONS' 

сторона клиента при запуске:

$.ajaxPrefilter(function(options, originalOptions, jqXHR) 
{ 
    options.crossDomain = 
    { 
     crossDomain: true 
    }; 
    options.xhrFields = 
    { 
     withCredentials: true 
    }; 
}); 

function csrfSafeMethod(method) 
{ 
    // these HTTP methods do not require CSRF protection 
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 
} 

$.ajaxSetup(
{ 
    crossDomain: false, // obviates need for sameOrigin test 
    beforeSend: function(xhr, settings) 
    { 
     if (!csrfSafeMethod(settings.type)) 
     { 
      xhr.setRequestHeader("X-CSRFToken", csrf); 
     } 
    } 
}); 

И тогда для хорошей меры в $ .ajax называют себя:

$.ajax(
{ 
    type: "POST", 
    url: theUrl, 
    data: theData, 
    contentType: 'application/x-www-form-urlencoded', 
    dataType: 'json', 
    xhrFields: 
    { 
     withCredentials: true 
    } 
}); 

Для я, то, что мне не хватало и ударило головой о стену, было этой частью:

xhrFields: 
{ 
    withCredentials: true 
} 

Надеюсь, это поможет кому-то.

+0

Интересно. Я считаю, что мы делаем все, что вы описали выше, за исключением установки crossDomain: false в запросах ajax. Я думаю, что мы явно установили crossDomain: true. Я займусь этим. Благодарю. – eswenson

Смежные вопросы