python - csrf验证失败请求被中断
Django CSRF检查失败,发出Ajax POST请求 (12)
对于遇到此问题并正在尝试调试的人员:
1)django csrf检查(假设你正在发送一个)在here
2)在我的情况下, settings.CSRF_HEADER_NAME
被设置为'HTTP_X_CSRFTOKEN',并且我的AJAX调用正在发送一个名为'HTTP_X_CSRF_TOKEN'的头部,所以东西不起作用。 我可以在AJAX调用或django设置中更改它。
3)如果你选择改变它的服务器端,找到你的django的安装位置,并在csrf middleware
抛出一个断点。如果你使用的是virtualenv
,它会是这样的: ~/.envs/my-project/lib/python2.7/site-packages/django/middleware/csrf.py
import ipdb; ipdb.set_trace() # breakpoint!!
if request_csrf_token == "":
# Fall back to X-CSRFToken, to make things easier for AJAX,
# and possible for PUT/DELETE.
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')
然后,确保csrf
标记正确地源自request.META
4)如果你需要改变你的头文件等 - 改变你的设置文件中的变量
我可以通过我的AJAX文章使用一些帮助来遵守Django的CSRF保护机制。 我按照这里的方向:
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/
我已经完全复制了他们在该页面上的AJAX示例代码:
http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
我在xhr.setRequestHeader
调用之前放置了一个打印getCookie('csrftoken')
的内容的警报,并且它确实填充了一些数据。 我不确定如何验证令牌是否正确,但我鼓励它发现并发送内容。
但是Django仍然拒绝我的AJAX帖子。
这是我的JavaScript:
$.post("/memorize/", data, function (result) {
if (result != "failure") {
get_random_card();
}
else {
alert("Failed to save card data.");
}
});
这是我从Django看到的错误:
[23 / Feb / 2011 22:08:29]“POST / memorize / HTTP / 1.1”403 2332
我确定我错过了一些东西,也许这很简单,但我不知道它是什么。 我搜索了一下,看到了一些关于通过csrf_exempt
装饰器关闭我的视图的CSRF检查的信息,但是我发现它没有吸引力。 我已经试过了,它可以工作,但我宁愿让我的POST按照Django设计的方式工作,如果可能的话。
以防万一它是有用的,这是我的观点在做什么的主要内容:
def myview(request):
profile = request.user.profile
if request.method == 'POST':
"""
Process the post...
"""
return HttpResponseRedirect('/memorize/')
else: # request.method == 'GET'
ajax = request.GET.has_key('ajax')
"""
Some irrelevent code...
"""
if ajax:
response = HttpResponse()
profile.get_stack_json(response)
return response
else:
"""
Get data to send along with the content of the page.
"""
return render_to_response('memorize/memorize.html',
""" My data """
context_instance=RequestContext(request))
感谢您的回复!
{% csrf_token %}
将<form></form>
html <form></form>
模板放在<form></form>
翻译为:
<input type='hidden' name='csrfmiddlewaretoken' value='Sdgrw2HfynbFgPcZ5sjaoAI5zsMZ4wZR' />
那么为什么不把它像这样写在你的JS中呢:
token = $("#change_password-form").find('input[name=csrfmiddlewaretoken]').val()
然后通过它,例如做一些POST,如:
$.post( "/panel/change_password/", {foo: bar, csrfmiddlewaretoken: token}, function(data){
console.log(data);
});
一个CSRF令牌分配给每个会话(即每次登录时)。 因此,在希望获取用户输入的某些数据并将其作为ajax调用发送给受csrf_protect装饰器保护的某个函数之前,请尝试在从用户获取此数据之前查找正在调用的函数。 例如,必须呈现用户输入数据的某个模板。 该模板正在被某个函数渲染。 在这个函数中,你可以得到csrf标记,如下所示:csrf = request.COOKIES ['csrftoken']现在在上下文字典中传递这个csrf值,使得模板被渲染。 现在在这个模板中写下这一行:现在在你的javascript函数中,在发出一个jax请求之前,写下:var csrf = $('#csrf')。val()这会选择传递给模板的令牌的值,并将其存储在变量CSRF。 现在在进行ajax调用时,在您的发布数据中也传递此值:“csrfmiddlewaretoken”:csrf
即使你没有实现django表单,这也可以工作。
事实上,这里的逻辑是:你需要令牌,你可以从请求中获得。 因此,您只需要在登录后立即找出正在调用的函数。获得此令牌后,可以再次调用ajax来获取它,或者将它传递给您的ajax可访问的某个模板。
似乎没有人提到过如何在纯JS中使用X-CSRFToken
头和{{ csrf_token }}
来做到这一点,所以这里有一个简单的解决方案,您不需要通过cookies或DOM进行搜索:
var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
xhttp.send();
使用Firefox和Firebug。 在触发ajax请求时打开“控制台”选项卡。 使用DEBUG=True
您可以获得好的django错误页面,您甚至可以在控制台选项卡中看到呈现的ajax响应html。
然后你会知道错误是什么。
在我的情况下,问题在于我从主服务器复制的nginx配置到临时配置,禁用了https,这在进程中的第二个配置中不需要。
我必须在配置中注释掉这两行才能使其重新工作:
# uwsgi_param UWSGI_SCHEME https;
# uwsgi_pass_header X_FORWARDED_PROTO;
如果您的表单在没有JS的情况下在Django中正确发布,您应该能够逐渐通过ajax进行增强,而不会发生任何黑客或混乱传递csrf标记。 只需序列化整个表单,并自动获取所有表单字段, 包括隐藏的csrf字段:
$('#myForm').submit(function(){
var action = $(this).attr('action');
var that = $(this);
$.ajax({
url: action,
type: 'POST',
data: that.serialize()
,success: function(data){
console.log('Success!');
}
});
return false;
});
我用Django 1.3+和jQuery 1.5+测试了这个。 显然这将适用于任何HTML表单,而不仅仅是Django应用程序。
如果有人为了做这项工作而苦苦挣扎,这对我有帮助:
import axios from 'axios';
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
来源: https://cbuelter.wordpress.com/2017/04/10/django-csrf-with-axios/ : https://cbuelter.wordpress.com/2017/04/10/django-csrf-with-axios/
我刚刚遇到了一些不同但类似的情况。 不是100%确定它是否可以解决您的问题,但是我通过设置POST参数'csrfmiddlewaretoken'并使用正确的cookie值字符串解决了Django 1.3的问题,该字符串通常由Django的带有'{%csrf_token%}'标记的模板系统。 我没有尝试Django,只是发生并在Django1.3上解决。 我的问题是,从表单中通过Ajax提交的第一个请求已成功完成,但第二次尝试从失败的完全相同,导致403状态,即使头文件'X-CSRFToken'正确放置了CSRF标记值如第一次尝试的情况一样。 希望这可以帮助。
问候,
浩
接受的答案很可能是一条红鲱鱼。 Django 1.2.4和1.2.5之间的区别是需要针对AJAX请求的CSRF令牌。
我在Django 1.3上遇到了这个问题,这是由于CSRF cookie不是首先设置的。 除非必须,否则Django不会设置cookie。 因此,在Django 1.2.4上运行的独占或严重ajax站点可能永远不会向客户端发送令牌,然后需要该令牌的升级会导致403错误。
理想的解决方法在这里: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form : http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#page-uses-ajax-without-any-html-form
但是你不得不等待1.4,除非这只是文档追踪代码
编辑
还要注意,后面的Django文档记录了jQuery 1.5中的一个错误,因此请确保您使用的是1.5.1或更高版本以及Django建议的代码: http://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax : http://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax
这是Django提供的一个不太详细的解决方案:
<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
// set csrf header
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
// Ajax call here
$.ajax({
url:"{% url 'members:saveAccount' %}",
data: fd,
processData: false,
contentType: false,
type: 'POST',
success: function(data) {
alert(data);
}
});
</script>
来源: https://docs.djangoproject.com/en/1.11/ref/csrf/ : https://docs.djangoproject.com/en/1.11/ref/csrf/
非jQuery的答案:
var csrfcookie = function() {
var cookieValue = null,
name = 'csrftoken';
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
};
用法:
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('X-CSRFToken', csrfcookie());
request.onload = callback;
request.send(data);