前言
CSRF,Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。他的产生由来是因为浏览器引起的。 比如用户访问A网站,A网站的html代码中有个提交数据,是发往B网站的,B网站受到浏览器发来的请求,实际上已经处理完毕,并且将返回数据发回了。但是这段数据在到达用户浏览器的时候,被浏览器拦截抛弃,这种现象是CSRF的由来。
也有部分人利用CSRF进行相关攻击,攻击原理如下:
Django中的CSRF
在Django中,有个中间件叫做django.middleware.csrf.CsrfViewMiddleware,如果加载后,在什么都不配置的情况下,跨站请求就会被阻挡,报错CSRF的错误。
解决上述问题,有两种方法,一种是在html中书写: {% csrf_token %}。另外一种是为每次ajax请求设置cookie
方法一:HTML中书写
<form action="/csrf/" method="post">
{% csrf_token %}
<input type="text" name="v">
<input type="submit" value="提交">
</form>
上述的{% csrf_token %}在页面中,会转换成input标签,标签中的内容类似如下:
<input type="hidden" name="csrfmiddlewaretoken" value="FS187YU8N8ixAOskUHTAEtkq0xJ3dirS2yJrCnN5IpAY9B9qpVHAQOhxoC4iV614">
这样的话,这次访问过去的请求的header中,就会带有csrftoken=QRzJCWrjRzJxHnG3phk1Nx60f96jfie7bILMEOi9gNEXTs6Mf9N6JyWzqJUMRogn的cookie,这样就不会受到浏览器的阻碍。
但是这么做是有弊端的。因为这段value字符串,在机器A可以用,如果在机器B上用,Django也会认为是合法的。
在书写的时候,路由函数也要注意使用render!!!
def csrf(request):
return render(request,'csrf.html')
方法二:为每次ajax请求设置cookie
通常我们的请求都是以ajax方式来提交的。因此这种方法更加需要明白。不多废话,直接贴代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="/csrf/" method="post"> {% csrf_token %} <input type="text" name="v" /> <input type="submit" value="提交" /> </form> <input type="button" value="Ajax提交" onclick="DoAjax();" /> <script src="/static/jquery-2.1.4.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> // 去cookie中获取值 var csrftoken = $.cookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ //当所有的ajax请求发送之前,进行这样的配置 beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); function DoAjax(){ $.ajax({ url: '/csrf/', type: 'POST', data: {'k1': 'v1'}, success: function (data) { console.log(data); } }) } </script> </body> </html>
上述的本质,就是去浏览器的cookie中获取csrftoken,在发送ajax请求的header的cookie中,加入csrftoken。
CSRF的单独使用
通常情况下,在settings的文件中,载入csrf的配置后,CSRF会对全局的url产生效果。那么,如果在settings中没有加载CSRF,CSRF还能使用么?答案是肯定的。
from django.views.decorators.csrf import csrf_exempt,csrf_protect
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。