(Django) AJAX 请求的 CSRF 验证在 Chrome 而不是 Firefox 中工作
Posted
技术标签:
【中文标题】(Django) AJAX 请求的 CSRF 验证在 Chrome 而不是 Firefox 中工作【英文标题】:(Django) CSRF Verification for AJAX requests working in Chrome but not Firefox 【发布时间】:2016-01-18 10:00:45 【问题描述】:正如标题所述,我的 (Django) CSRF 验证在 Chrome 中有效,但在 Firefox 中无效,我想知道为什么我可以解决这个问题。
我将它包含在我的 base.html 文件的 head 标记中,我的应用程序中的所有其他文件都从该标记中扩展:
base.html,head 标签的底部
<script>
$(document).ready(function()
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;
var csrftoken = getCookie('csrftoken');
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) && !this.crossDomain)
xhr.setRequestHeader("X-CSRFToken", csrftoken);
);
);
</script>
我在一个名为 browse.js 的文件中有这段代码,它需要向我自己的服务器发出 ajax 请求。
browse.js
Template =
setup : function()
Template.events.csrf();
// etc. etc.
,
events:
csrf : function()
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;
var csrftoken = getCookie('csrftoken');
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) && !this.crossDomain)
xhr.setRequestHeader("X-CSRFToken", csrftoken);
);
,
//etc. etc.
//The actual ajax request
Data =
api :
ajax_get_listings : function(cb)
var g, i, o, _ref;
_ref = [
$('#ci').val(),
$('#co').val(),
$('#guests').val()],
i = _ref[0],
o = _ref[1],
g = _ref[2];
if (g)
console.log('getting listings');
return $.ajax(
url:'/api/get_listing_items/',
type: 'POST',
datatype:'json',
data:
available_start_date: i,
available_end_date: o,
max_guests: g
,
success: function(d)
if (d.listings !== null)
Data.listings._results = [];
console.log(d);
var l = $.parseJSON(
$("<textarea/>").html(d.listings).text());
console.log(l);
data = l;
console.log(data);
return cb(data);
else
$('#ct').text('No listings found for your search criteria. Please keep searching!');
,
);
,
,
//etc. etc
同样,这在 Chrome 中运行良好。当我在 Firefox 上时,它只会给我一个 403 Forbidden。这是回溯:
追溯
标题
view source
Content-Type
text/html
Date
Mon, 19 Oct 2015 22:06:07 GMT
Server
WSGIServer/0.1 Python/2.7.3
Vary
Cookie
X-Frame-Options
SAMEORIGIN
view source
Accept
*/*
Accept-Encoding
gzip, deflate
Accept-Language
en-US,en;q=0.5
Cache-Control
no-cache
Connection
keep-alive
Content-Length
54
Content-Type
application/x-www-form-urlencoded; charset=UTF-8
Cookie
_ga=GA1.1.1619904474.1445292335; _gat=1; TawkConnectionTime=0; __tawkuuid=e||127.0.0.1||mnW1PFpM4y26O8w
+2HatshrE3nWV4w3xD7SAtEMYGtV647bMojOwsqzNlPdxYCdB||2; Tawk_560d98fcc096ea637ec4b8c0=vs15.tawk.to:443
||0
DNT
1
Host
127.0.0.1:8008
Pragma
no-cache
Referer
http://127.0.0.1:8008/properties/
User-Agent
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0
X-CSRFToken
null
X-Requested-With
XMLHttpRequest
响应
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="robots" content="NONE,NOARCHIVE">
<title>403 Forbidden</title>
<style type="text/css">
html * padding:0; margin:0;
body * padding:10px 20px;
body * * padding:0;
body font:small sans-serif; background:#eee;
body>div border-bottom:1px solid #ddd;
h1 font-weight:normal; margin-bottom:.4em;
h1 span font-size:60%; color:#666; font-weight:normal;
#info background:#f6f6f6;
#info ul margin: 0.5em 4em;
#info p, #summary p padding-top:10px;
#summary background: #ffc;
#explanation background:#eee; border-bottom: 0px none;
</style>
</head>
<body>
<div id="summary">
<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>
<p>You are seeing this message because this site requires a CSRF cookie when submitting forms. This
cookie is required for security reasons, to ensure that your browser is not being hijacked by third
parties.</p>
<p>If you have configured your browser to disable cookies, please re-enable them, at least for this
site, or for 'same-origin' requests.</p>
</div>
<div id="info">
<h2>Help</h2>
<p>Reason given for failure:</p>
<pre>
CSRF cookie not set.
</pre>
<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
<a
href='http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ref-contrib- csrf'>Django's
CSRF mechanism</a> has not been used correctly. For POST forms, you need to
ensure:</p>
<ul>
<li>Your browser is accepting cookies.</li>
<li>The view function uses <a
href='http://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing- context-requestcontext'
><code>RequestContext</code></a>
for the template, instead of <code>Context</code>.</li>
<li>In the template, there is a <code>% csrf_token
%</code> template tag inside each POST form that
targets an internal URL.</li>
<li>If you are not using <code>CsrfViewMiddleware</code>, then you must use <code>csrf_protect</code> on any views that use the <code>csrf_token</code>
template tag, as well as those that accept the POST data.</li>
</ul><p>You're seeing the help section of this page because you have <code>DEBUG =
True</code> in your Django settings file. Change that to <code>False</code>,
and only the initial error message will be displayed. </p>
<p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
</div>
</body>
</html>
可能出了什么问题?
已解决:我将 @ensure_csrf_cookie 放在获取 cookie 的视图上(不是 ajax 请求调用的函数——这让我感到困惑)。现在 Firefox 上不再出现 403。耶
【问题讨论】:
【参考方案1】:在您的请求标头中,我看到:
X-CSRFToken null
所以我的猜测是 cookie 是在 Firefox 中设置的。也许它已经在之前的会话中在 Chrome 中设置了。
The Django docs explain one reason why this may be:
警告
如果您的视图未呈现包含 csrf_token 的模板 模板标签,Django 可能不会设置 CSRF 令牌 cookie。这是 在表单被动态添加到页面的情况下很常见。到 针对这种情况,Django 提供了一个视图装饰器,它强制 cookie的设置:ensure_csrf_cookie()。
尝试在您的views.py 中导入ensure_csrf_cookie
装饰器并用它包装您的基础视图。例如:
from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def base_view(request):
# do stuff
return render('base.html', ...)
我不确定这是否是根本问题,但我希望这会有所帮助!
【讨论】:
以上是关于(Django) AJAX 请求的 CSRF 验证在 Chrome 而不是 Firefox 中工作的主要内容,如果未能解决你的问题,请参考以下文章
错误:“CSRF 验证失败。请求中止。”在 Django 中使用 jquery ajax 时
Django(十六)基于模板的登录案例:登录装饰器csrf攻击方式及防护ajax的Post 的csrf开启写法生成验证码加验证码登录反向解析+传参
带有 django 的 JQuery AJAX 获取 csrf 错误 403
django 页面进行ajax post提交时,页面要添加{% csrf_token %}