使用Django发POSTt请求的时候经常会遇到Forbidden的错误,然后直接了当的方法就是去setting里面吧csrf中间件注释掉,其实csrf是django给我们提供的防护措施.
CSRF就是一种攻击方式,原理大概是你去A网站登录后本地留下了A网站的cookie,然后去B网站访问收到了CSRF的攻击,拿到了你A网站的cookie,然后攻击者用这个cookie去请求A网站,盗取你的信息财物等.
具体这个博客写得很好:戳CSRF
这里我们主要讲django 中csrf防护的原理和设置.
1.csrf防护在Django中就是一个中间件,生成token验证,token验证就是你要拿到一张牌(一串字符串),django认识这个字符串,才让你访问.
#django settings.py 里面 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',#就是这货 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
2.Form请求中的csrf:
我们写好一盒form表单,提交方式写为post的时,点提交会出现以下页面:
Forbidden (403) CSRF verification failed. Request aborted. Help Reason given for failure: CSRF token missing or incorrect. In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure: Your browser is accepting cookies. The view function passes a request to the template's render method. In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL. If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data. The form has a valid CSRF token. After logging in in another browser tab or hitting the back button after a login, you may need to reload the page with the form, because the token is rotated after a login. You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed. You can customize this page using the CSRF_FAILURE_VIEW setting.
错误中也说明了解决方式:在form表单中加入{
%
csrf_token
%
}:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/fm001/myCSRF/" method="post"> name: <input type="text"> <input type="submit" value="提交"> {% csrf_token %} </form> </body> </html>
我们再发post请求就可以了,检查发现{% csrf_token %} 在页面上生成了这串东西, 我们提交请求的时候会带着这个东西去请求,而这个东西就是django给我的,django会识别是不是这货
3:Ajax请求中的csrf:
写好html页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="/static/jquery-3.2.1.min.js"></script> </head> <body> <form action="/fm001/myCSRF/" method="post"> name: <input type="text"> <input type="submit" value="提交"> <input id="but" type="button" value="ajax提交"> </form> </body> <script> $("#but").click(function () { $.ajax({ url:"/fm001/myCSRF/", type:"POST", data:{"xx":"yy"}, success:function (arg) { alert("ok") } }) }) </script> </html>
提交后出现如下错误:Forbidden (CSRF token missing or incorrect.): /fm001/myCSRF/
这就是我们没有提交token给django,需要在请求头里面加上token值,用jq获取cookie,所以导入jquery.cookie.js 具体:
<script>
$("#but").click(function () {
$.ajax({
url:"/fm001/myCSRF/",
type:"POST",
data:{"xx":"yy"},
headers:{"X-CSRFToken":$.cookie("csrftoken")},
success:function (arg) {
alert("ok")
}
})
})
</script>
这样提交就可以了.
为了方便,不每次发ajax请求都去写headers,可以设置ajax请求每次发送之前加上添加token到headers的操作:
$.ajaxSetup({
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
当然的django中也可以试着那些请求需要token,那些不需要,django提供了装饰器:
from dajngo.views.decorators.csrf import csrf_protect,csrf_exempt @csrf_protect,#为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。加载views函数上就可以了. @csrf_exempt,#取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。