一、CSRF是什么
跨站请求伪造(CSRF)与跨站请求脚本正好相反。跨站请求脚本的问题在于,客户端信任服务器端发送的数据。跨站请求伪造的问题在于,服务器信任来自客户端的数据。
二、无CSRF时存在的隐患
跨站请求伪造是指攻击者通过HTTP请求江数据传送到服务器,从而盗取回话的cookie。盗取回话cookie之后,攻击者不仅可以获取用户的信息,还可以修改该cookie关联的账户信息。
三、Form提交(CSRF)
csrf验证其实是对http请求中一段随机字符串的验证,
如果没有这样一段随机字符串做验证,我们只要在另一个站点,写一个表单,提交到这个地址下,是一样可以发送数据的,这样就造成了极大的安全隐患。而我们新添加的csrf_token就是在我们自己的站点中,设置的隐藏参数,用来进行csrf验证。
四、Ajax提交 (CSRF)
我们可以从cookie中获取到这个随机字符串,要在引入jquery文件之后引入:
var csrftoken = $.cookie('csrftoken');
# 或通过标签取到
var csrftoken = $('input[name="csrfmiddlewaretoken"]').val();
这样变量csrftoken取到的就是我们的随机字符串;但是如果后台想要去接收这个随机字符串,也应该需要一个key,那这个key是什么?我们可以通过查找配置文件,通过控制台输出的方式验证这个key:
from django.conf import settings
print(settings.CSRF_HEADER_NAME)
最后输出的是:
HTTP_X_CSRFTOKEN
但这里需要注意的是,HTTP_X_CSRFTOKEN并不是请求头中发送给django真正拿到的字段名,前端发过去真正的字段名是:
X-CSRFtoken
将字段放入headers:
headers:{"X-CSRFToken":csrftoken},
放入data:
data:{"user":user,"csrfmiddlewaretoken":csrftoken}
那为什么从Django的控制台输出会得到HTTP_X_CSRFTOKEN呢?其实我们前端的请求头X-CSRFtoken发送到后台之后,django会做一个名字处理,在原来的字段名前家一个HTTP_,并且将原来的小写字符变成大写的,“-”会处理成下划线“_”,所以会有这两个字段的不一样。但本质上他们指向的都是同一个字符串。知道这一点之后,那么我们前端就可以真正地发起含有CSRF请求头的数据请求了。
Title
在页面中点击按钮之后,会发现请求成功!
那么这个时候有人会问,难道所有的ajax请求,都需要这样获取一次写进去吗,会不会很麻烦。针对这一点,jquery的ajax请求中为我们封装了一个方法:ajaxSetup,它可以为我们所有的ajax请求做一个集体配置,所以我们可以进行如下改造,这样不管你的ajax请求有多少,都可以很方便地进行csrf验证了:
Title
五、csrf装饰器配置
在平时场景中,并不一定所有的接口验证都需要进行csrf验证,我们采用的是在settings.py中间件配置进行全局配置,如果遇到不需要验证的,我们可以采用局部禁用。
FBV
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_protect #局部使用
def index(request):
.....
@csrf_exempt #局部禁用
def login(request):
.....
CBV
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.shortcuts import render, HttpResponse
from django.views import View
class Cs(View):
#@method_decorator(csrf_exempt)
@method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return HttpResponse('GET,响应内容')
def post(self, request, *args, **kwargs):
return HttpResponse('Post,响应内容')
或
六、Django加装饰器
from django.utils.decorators import method_decorator
# 1.方法
@csrf_protect
def get(request):
pass
# 2.类上
@method_decorator(wraper,name="dispatch")
class Foo(View):
# @method_decorator(csrf_exempt)
# @method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self,request):
pass
def post(self,request):
pass
注意:csrf必须加在dispatch上
七、手动将csrftoken写入cookie的方法
手动设置,在view 中添加(建议采用2,3,4种方法)
request.META["CSRF_COOKIE_USED"] = True
手动调用 csrf 中的 get_token(request) 或 rotate_token(request) 方法。
from django.middleware.csrf import get_token ,rotate_token
def server(request):
# get_token(request) // 两者选一
# rotate_token(request) // 此方法每次设置新的cookies
return render(request, ‘server.html‘)
在HTML模板中添加 {% csrf_token %}
在需要设置cookie的视图上加装饰器 ensure_csrf_cookie()
from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def server(request):
return render(request,'server.html')