如何 retrieve/provide CSRF 令牌 to/from Django 作为 API
How to retrieve/provide a CSRF token to/from Django as an API
我正在开发一个使用 Django REST Framework 作为后端的项目(假设在 api.somecompany.com
但有一个 React.js 前端(在 www.somecompany.com
)不由发出 AJAX 个请求的 Django。
因此,我不能使用 Django 的传统方法让模板像这样包含 CSRF 令牌 <form action="." method="post">{% csrf_token %}
我可以向 Django REST Framework 的 api-auth\login\
url 发出请求,这将 return 这个 header:
Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/
- 但我无法检索此 cookie 以通过 X-CSRFToken
发送回我的 AJAX 请求(我的理解是单独的子域),而且它似乎不是自动包含。
这是我的相关代码:
// using jQuery
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;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
当页面加载时,我调用它来确保我有一个令牌:
$.ajax(loginUrl, { method: "OPTIONS", async: false })
.done(function(data, textStatus, jqXHR) {
console.log(jqXHR)
app.csrftoken@ = $.cookie("csrftoken")
console.log($.cookie("csrftoken"))
console.log(app.csrftoken)
})
.fail(function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
});
这不是很清楚,但我还没有向自己证明这个概念。
当前端和后端处于不同 ports/domains 时,'correct' 验证/防止 CSRF 的方法是什么?
事实上,您可以使用允许的请求来源白名单,使它在 CSRF 保护下工作。
要完成这项工作,您将不得不使用 Cross-Origin Resource Sharing
(CORS)。为此,我建议创建一个中间件 class 来设置您的 cross-sharing 凭据。有一个 great gist 概述了如何在跨源 HTTP 请求 header 中使用一些构建。如果需要,您可以通过更改请求的原始参考值,以这种方式通过中间件插入 CSRF 令牌。
django-cors-headers app does this for you. You can see how they've negotiated the CSRF tokens in their middleware file,如果你有兴趣的话。
请参阅 Django REST CORS Docs 了解更多信息(他们建议使用 django-cors-headers)。
如果您仍然遇到困难,请尝试:
- 将 AJAX 请求的
crossDomain
参数设置为 True
。有时,如果未指定,jQuery 将不会处理请求。
- 如果您仍然没有在请求中收到令牌 header,请尝试在您的视图方法周围附加
ensure_csrf_cookie()
装饰器。有时,当页面上没有 {% csrf_token %}
模板标记时(如果您不呈现表单),Django 根本不会在请求中包含令牌。
我正在开发一个使用 Django REST Framework 作为后端的项目(假设在 api.somecompany.com
但有一个 React.js 前端(在 www.somecompany.com
)不由发出 AJAX 个请求的 Django。
因此,我不能使用 Django 的传统方法让模板像这样包含 CSRF 令牌 <form action="." method="post">{% csrf_token %}
我可以向 Django REST Framework 的 api-auth\login\
url 发出请求,这将 return 这个 header:
Set-Cookie:csrftoken=tjQfRZXWW4GtnWfe5fhTYor7uWnAYqhz; expires=Mon, 01-Aug-2016 16:32:10 GMT; Max-Age=31449600; Path=/
- 但我无法检索此 cookie 以通过 X-CSRFToken
发送回我的 AJAX 请求(我的理解是单独的子域),而且它似乎不是自动包含。
这是我的相关代码:
// using jQuery
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;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
当页面加载时,我调用它来确保我有一个令牌:
$.ajax(loginUrl, { method: "OPTIONS", async: false })
.done(function(data, textStatus, jqXHR) {
console.log(jqXHR)
app.csrftoken@ = $.cookie("csrftoken")
console.log($.cookie("csrftoken"))
console.log(app.csrftoken)
})
.fail(function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
});
这不是很清楚,但我还没有向自己证明这个概念。
当前端和后端处于不同 ports/domains 时,'correct' 验证/防止 CSRF 的方法是什么?
事实上,您可以使用允许的请求来源白名单,使它在 CSRF 保护下工作。
要完成这项工作,您将不得不使用 Cross-Origin Resource Sharing
(CORS)。为此,我建议创建一个中间件 class 来设置您的 cross-sharing 凭据。有一个 great gist 概述了如何在跨源 HTTP 请求 header 中使用一些构建。如果需要,您可以通过更改请求的原始参考值,以这种方式通过中间件插入 CSRF 令牌。
django-cors-headers app does this for you. You can see how they've negotiated the CSRF tokens in their middleware file,如果你有兴趣的话。
请参阅 Django REST CORS Docs 了解更多信息(他们建议使用 django-cors-headers)。
如果您仍然遇到困难,请尝试:
- 将 AJAX 请求的
crossDomain
参数设置为True
。有时,如果未指定,jQuery 将不会处理请求。 - 如果您仍然没有在请求中收到令牌 header,请尝试在您的视图方法周围附加
ensure_csrf_cookie()
装饰器。有时,当页面上没有{% csrf_token %}
模板标记时(如果您不呈现表单),Django 根本不会在请求中包含令牌。