在慕课网制作(三)我挖了几个坑,今天就是来填坑的,本章主要是介绍什么是csrf。
什么是csrf首先我们设想一个情境,我们要给某个人转账,张三知道了这个接口是一个post请求,转账就是通过这个点击这个请求。然后张三伪造了一个网站,当我们点击了这个接口,他就自动往张三的账户上进行了转账,因为使我们在本地进行点击,session也是在我们这台电脑上,银行后台就认为是我主动点击的。也退不回来了,那咋办????
有办法,聪明的孩子 (疯狂暗示) 在一下子想到了我可以在 用get请求的网页的时候就在form表单中生成一个随机字符串 在post请求的时候也把这个字符串请求过去,就想到与额外的加了一个锁,虽然说这个方法还有一定的局限性,但是目前的方法就这一个了。
django中实现 from提交在django的setting.py中他是默认开启了全局的csrf验证,也就是说如果在进行post请求的时候没有带csrf就会报错,我们可以在这里设置csrf验证的开启或关闭
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',
]
上面的这个字段存放的django运行的中间件,现在不在我们探讨的返回
'django.middleware.csrf.CsrfViewMiddleware',
这一个就是用来验证csrf 我们可以把它注释掉,这样就可以让全局都不在验证post
如果我们想要进行csrf给自己网站增加点安全性,我们可以在前段网页的form表单下 加一个 {% csrf_token %} django就自动加了一个隐藏的input 里面存放随机的字符串,在请求的时候 django就自动对着字符串进行判断。
ajex提交数据下面的 是我转载别人的 关于ajex 看说的挺不错的。
csrf中间件要验证的随机字符串存放在了form表单当中,发送到了后台,那么如果我们使用的是ajax异步请求,是不是也要传送这样一个类似的字符串呢?答案是肯定的,但这个字符串又该来自哪里?其实它来自cookie,在上面的那个小例子当中,我们打开F12元素审查,会发现,在cookie中也存放这样一个csrftoken:
所以下面呢我们就再聊一下ajax请求中如何进行。
首先我们引入两个js文件放在工程项目的static当中,这两个文件是jquery的库文件,方便我们进行请求操作
然后我们把之前的login.html做一个修改:
Title
这个时候我们打开界面,点击按钮,会发现http请求发送403错误,很明显我们直接发送请求是不合适的,并没有带随机字符串过去:
所以,我们应该先从cookie中获取到这个随机字符串,这个随机字符串的名字,我们可以通过之前的验证得出是“csrftoken”:
var csrftoken = $.cookie('csrftoken');
这样变量csrftoken取到的就是我们的随机字符串;但是如果后台想要去接收这个随机字符串,也应该需要一个key,那这个key是什么?我们可以通过查找配置文件,通过控制台输出的方式验证这个key:
from django.conf import settings print(settings.CSRF_HEADER_NAME)
最后输出的是:
HTTP_X_CSRFTOKEN
但这里需要注意的是,HTTP_X_CSRFTOKEN并不是请求头中发送给django真正拿到的字段名,前端发过去真正的字段名是:
X-CSRFtoken
那为什么从Django的控制台输出会得到HTTP_X_CSRFTOKEN呢?其实我们前端的请求头X-CSRFtoken发送到后台之后,django会做一个名字处理,在原来的字段名前家一个HTTP_,并且将原来的小写字符变成大写的,“-”会处理成下划线“_”,所以会有这两个字段的不一样。但本质上他们指向的都是同一个字符串。知道这一点之后,那么我们前端就可以真正地发起含有CSRF请求头的数据请求了。
Title
在页面中点击按钮之后,会发现请求成功!
那么这个时候有人会问,难道所有的ajax请求,都需要这样获取一次写进去吗,会不会很麻烦。针对这一点,jquery的ajax请求中为我们封装了一个方法:ajaxSetup,它可以为我们所有的ajax请求做一个集体配置,所以我们可以进行如下改造,这样不管你的ajax请求有多少,都可以很方便地进行csrf验证了:
Title
装饰器
在有些时候我们想要在某一个请求下不使用 csrf,有些请求使用,我们可以在对应的 方法上面添加添加一个django自带的装饰器来来进行标识
from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_protect
def index(request):
.....
@csrf_exempt
def login(request):
.....
@csrf_protect 是 开启csrf验证的装饰器,@csrf_exempt是关闭csrf验证的装饰器。



