[Django] CSRF应用以及加装饰器

一、CSRF是什么
跨站请求伪造(CSRF)与跨站请求脚本正好相反。跨站请求脚本的问题在于,客户端信任服务器端发送的数据。跨站请求伪造的问题在于,服务器信任来自客户端的数据。

二、无CSRF时存在的隐患
跨站请求伪造是指攻击者通过HTTP请求江数据传送到服务器,从而盗取回话的cookie。盗取回话cookie之后,攻击者不仅可以获取用户的信息,还可以修改该cookie关联的账户信息。

三、Form提交(CSRF)
csrf验证其实是对http请求中一段随机字符串的验证,
如果没有这样一段随机字符串做验证,我们只要在另一个站点,写一个表单,提交到这个地址下,是一样可以发送数据的,这样就造成了极大的安全隐患。而我们新添加的csrf_token就是在我们自己的站点中,设置的隐藏参数,用来进行csrf验证。

四、Ajax提交 (CSRF)

我们可以从cookie中获取到这个随机字符串,要在引入jquery文件之后引入:

<script src="{% static 'js/jquery.cookie.js' %}"></script>
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请求头的数据请求了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user" />
        <input type="text" name="pwd" />
        <input type="checkbox" name="rmb" value="1" /> 10s免登录
        <input type="submit" value="提交" />
        <input id="btn" type="button" value="按钮">
    </form>
 
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        var csrftoken = $.cookie('csrftoken');
        $(function () {
            $('#btn').click(function () {
                $.ajax({
                    url:'/login/',
                    type:"POST",
                    data:{'username':'root','pwd':'123123'},
                    header:{'X-CSRFToken':csrftoken},
                    success:function (arg) {                 
                    }
                })
            })
        })
    </script>
</body>
</html>

在页面中点击按钮之后,会发现请求成功!

那么这个时候有人会问,难道所有的ajax请求,都需要这样获取一次写进去吗,会不会很麻烦。针对这一点,jquery的ajax请求中为我们封装了一个方法:ajaxSetup,它可以为我们所有的ajax请求做一个集体配置,所以我们可以进行如下改造,这样不管你的ajax请求有多少,都可以很方便地进行csrf验证了:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login/" method="POST">
        {% csrf_token %}
        <input type="text" name="user" />
        <input type="text" name="pwd" />
        <input type="checkbox" name="rmb" value="1" /> 10s免登录
        <input type="submit" value="提交" />
        <input id="btn" type="button" value="按钮">
    </form>
 
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        var csrftoken = $.cookie('csrftoken');
        
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            }
        });
 
        $(function () {
            $('#btn').click(function () {
                $.ajax({
                    url:'/login/',
                    type:"POST",
                    data:{'username':'root','pwd':'123123'},
                    success:function (arg) {
                        
                    }
                })
            })
        });
    </script>
</body>
</html>

五、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的方法

  1. 手动设置,在view 中添加(建议采用2,3,4种方法)

    request.META["CSRF_COOKIE_USED"] = True
    
  2. 手动调用 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‘)
    
  3. 在HTML模板中添加 {% csrf_token %}

  4. 在需要设置cookie的视图上加装饰器 ensure_csrf_cookie()

    from django.views.decorators.csrf import ensure_csrf_cookie
     
    @ensure_csrf_cookie
    def server(request):
        return render(request,'server.html')
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Moke丶青

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值