csrf
跨站点请求伪造(Cross—Site Request Forgery),具体过程如下:
- 用户登录后访问某网站A,未退出。
- 被技术手段欺骗点击(比如被修改了的邮件链接),进行了个人隐私的操作(比如金钱的转账)。
- 这种欺骗用户浏览器,让其以用户的名义间接控制用户账户的操作就是跨站点请求伪造。
这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
解决方案
- 检验http headers中的Referer,它的内容就是这次http请求的网站地址。对于服务端来说,在请求头部信息里我们可以过滤出有害请求地址的黑名单。
- 添加随机参数token,来每一次请求到来后,对比token值来验证是否是来自本服务器的信任。
在我们在post请求的时候可能会有这样的错误:
这就是我们在setting中设置了Csrf中间件后,在请求中没有设置csrf token的问题,导致服务器开启了csrf验证环节吗,但是发现请求中并没有token,所以无法对比返回403错误。
首先可以注掉这个中间件不使用,django就会放弃对csrf的检验。但这样就算是放弃了django原生的csrf安全组件,后果可能会造成跨站伪造,当然如果是测试就注释掉。
另外,django给出了另一种解决办法,它提供了csrf_exempt这个装饰器,在不注释此中间件的情况下,在view外加上这个装饰器,可以在调用csrfmiddleware的process_view中跳过。源码如下:
csrf_exempt装饰器会先给视图函数注册一个csrf_exempt为True的属性,当处理process_view时,会判断此值是否为True,是则跳过下面逻辑。
以上我们都在想着这么去掉这段功能,如果要正常使用它怎么办?
如果使用的是django自带的render页面模型,我们需要在template中加入csrf_token这个参数,这个参数会根据配置是否存入session。在post请求时,需要加上{“csrfmiddlewaretoken”: csrf_token},这样中间件就拿到前端上传的token和自己有的进行对比,在验证是否伪造请求。
最好要在视图函数前同样加上@csrf_protect这个装饰器,表示支持csrf中间件的检查。
如果是前后端分离,也可以借用csrf中间件的一套,只不过需要把生成token的逻辑单独维护一个api,把原来render的逻辑改到api上,后面我们每次post请求的时候,先拿到token,再添加到请求参数里面提交,之后验证的逻辑就和原逻辑一致了。