• django第五章 CSRF






    CSRF

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


    无CSRF时存在的隐患

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


    CSRF在Django中应用

    django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。使用前需要在配置文件 settings.py 中开启。
    而对于django中设置防跨站请求伪造功能有分为全局和局部。

    点击查看代码
    全局:
    中间件 django.middleware.csrf.CsrfViewMiddleware
    
    局部:
    @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
    @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
    
    注意:from django.views.decorators.csrf import csrf_exempt,csrf_protect
    

    • 处理csrf四种方法
      django 第一次响应来自某个客户端的请求时(get方式),会在服务器端随机生成一个 token,然后把这个 token 写在用户请求的 cookie 里,同时也会给客户端页面发送一个随机的 token (form表单中以{% csrf_token %}方式获取)用以认证。之后客户端每次以 POST 方式向服务端提交请求时,都会带上这个 token,这样就能避免被 CSRF 攻击。

    方式:

    1. 在返回的 HTTP 响应的 cookie 里,django 会为你添加一个 csrftoken 字段,其值为一个自动生成的 token;
    2. 在所有的 POST 表单中,必须包含一个 csrfmiddlewaretoken 字段;
    3. 在处理 POST 请求之前,django 会验证这个请求的 cookie 里的 csrftoken 字段的值和提交的表单里的 csrfmiddlewaretoken 字段的值是否一样。如果一样,则表明这是一个合法的请求;否则,这个请求可能是来自于别人的 csrf 攻击,返回 403 Forbidden
    4. 在所有 ajax POST 请求里,添加一个 X-CSRFTOKEN header,其值为 cookie 里的 csrftoken 的值。



    • Form提交(CSRF)

    那么在Django中CSRF验证大体是一个什么样的原理呢?下面通过一个小例子来简单说明一下:

    1. 先在settings.py配置文件中开启中间件:
      MIDDLEWARE = [ 'django.middleware.csrf.CsrfViewMiddleware', ]

    1. 在app01的views.py中写一个简单的后台:
    点击查看代码
    def csrf1(request):
        if request.method == 'GET':
            return render(request, 'csrf1.html')
        elif request.method == 'POST':
            return HttpResponse('CSRF 验证通过!')
    

    1. 在 csrf1.html 模板中写入:
    点击查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>CSRF</title>
    </head>
    <body>
        <form method="POST" action="/csrf1.html">
            <input type="text" name="test" />
            <input type="submit" value="提交"/>
        </form>
    </body>
    </html>
    

    1. 启动Django服务后,进入页面显示内容:

    那么如果这个时候,我们点击登陆提交,django会因为无法通过csrf验证返回一个403:


    1. 而csrf验证其实是对http请求中一段随机字符串的验证,那么这段随机字符串从何而来呢?这个时候我们尝试把csrf1.html做一个修改添加一句 {% csrf_token %}

    直接在form表单中添加:

    ​ {% csrf_token %} -----> 转换成一个hidden属性的input标签

    ​ {{ csrf_token }} -----> 直接获取csrf的随机字符串

    注意:本地的cookies中也会添加随机字符串 ---> 注意key名

    点击查看代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>CSRF</title>
    </head>
    <body>
        <form method="POST" action="/csrf1.html">
            {% csrf_token %}
            <input type="text" name="test" />
            <input type="submit" value="提交"/>
        </form>
    </body>
    </html>
    

    1. 添加 {%csrf_token%} 之后,我们再通过浏览器元素审查,就会发现一段新的代码:

    并且 cookies 中也携带了 csrf_token 随机码数据:

    Django在html中创建一个基于input框value值的随机字符串 ,当再次提交数据时,就会通过 csrf 验证机制:

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



    全站禁用

    整个框架不使用csrf安全机制,直接在settings.py文件中注销,整个网站都不再应用。
    'django.middleware.csrf.CsrfViewMiddleware',



    局部禁用:全局使用,但是某些函数不需要应用

    settings.py文件中不注销

    MIDDLEWARE = [ 'django.middleware.csrf.CsrfViewMiddleware', ]

    在项目的views.py函数中导入模块,给函数或是类加上对应方法的装饰器:

    点击查看代码
    from django.views.decorators.csrf import csrf_exempt,csrf_protect
     
    @csrf_exempt   #不再做检测!其他没加装饰器的函数还是会检测
    def csrf1(request):
        if request.method == 'GET':
            return render(request,'csrf1.html')
        elif request.method == 'POST':
            return HttpResponse('CSRF 验证通过!')
    



    局部使用:全局不使用,但是某些函数需要应用

    settings.py文件中注销
    MIDDLEWARE = [ # 'django.middleware.csrf.CsrfViewMiddleware', ]

    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    
    @csrf_protect     #全站不用,某个函数需要使用认证
    def csrf1(request):
    	if request.method == 'GET':
    		return render(request,'csrf1.html')
    	elif request.method == 'POST':
            return HttpResponse('CSRF 验证通过!')
    



    特殊CBV:在CBV应用中

    django 不认给类内的函数名上添加装饰器,只能是在类上添加。
    同时django限制若是应用装饰器,必须用它的方法去添加,同时添加的语法格式也有限制。

    点击查看代码
    from django.views import View
    from django.utils.decorators import method_decorator  #必须使用这个方法
    # 语法:@method_decorator(装饰器函数名称或方法,name='被装饰的函数名')
    
    #先导入方法,然后装饰器以参数的形式添加,其次指定要添加这个方法的函数名<样式:name="函数名">
    
    @method_decorator(csrf_protect,name='dispatch')
    class Foo(View):
    	#请求来了,都是先执行类View的内置函数dispatch,然后再映射到对应的方法上!
    	#所以给dispatch添加上就相当于给所有的方法添加了
    	def get(self,request):
    		pass
    	def post(self,request):
    		pass
    
    点击查看代码
    ''' CBV中应用装饰器 '''
    
    #自定义的装饰器
    def wrapper(func):
    	def inner(*args,**kwargs):
    		return func(*args,**kwargs)
    	return inner
    
    # 1. 指定方法上添加装饰器
    class Foo(View):
        @method_decorator(wrapper)    #先导入方法,然后装饰器以参数的形式添加
        def get(self,request):
            pass
        def post(self,request):
            pass
    
    # 2. 在类上添加
    @method_decorator(wrapper,name='get') # name=方法名,写那个方法就是给谁加
    @method_decorator(wrapper,name='post') # name=方法名,写那个方法就是给谁加
    class Foo(View):
        def get(self,request):
            pass
        def post(self,request):
            pass
    



    Ajax 中POST方式提交时候,放置在data中携带CSRF

    <form method="POST" action="/csrf1.html">
    	{% csrf_token %}
    	<input id="user" type="text" name="user" />
    	<input type="submit" value="提交"/>
    	<a onclick="submitForm();">Ajax提交</a>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
    	function submitForm(){
    		var csrf = $('input[name="csrfmiddlewaretoken"]').val();
    		var user = $('#user').val();
    		$.ajax({
    			url: '/csrf1.html',
    			type: 'POST',
    			data: { "user":user,'csrfmiddlewaretoken': csrf}, 
                #注意csrf随机字符串,后台有固定的名字接收,这种方式是通过标签获取的对应值
                success:function(arg){
    				console.log(arg);	}
    		})
    	}
     </script>
    



    AJAX 中POST方式提交,信息放在请求头中,从cookies中获取的csrf随机字符串

    jquery.cookie.js官网下载地址:https://plugins.jquery.com/cookie/

    其它下载方式:https://www.jq22.com/jquery-info122

    <form method="POST" action="/csrf1.html">
    	{% csrf_token %}
    	<input id="user" type="text" name="user" />
    	<input type="submit" value="提交"/>
    	<a onclick="submitForm();">Ajax提交</a>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>  <!--# 插件:帮助我们自动分割cookie-->
    <script>
    	function submitForm(){
    		var token = $.cookie('csrftoken');  # 获取cookie值
    		var user = $('#user').val();
    		$.ajax({
    			url: '/csrf1.html',
    			type: 'POST',
    			headers:{'X-CSRFToken': token},  #注意: X-CSRFToken 是Django规定写法
    			data: { "user":user},
    			success:function(arg){
    				console.log(arg);	}
    		})
    	}
    </script>
    



    django csrf 注意事项

    注意:ajax POST提交的时候,csrf-token 随机字符串直接放在data数据中的方式为:data:{csrfmiddlewaretoken:"{{ csrf_token }}"}

    若是导入自己写的JS文件,那上述方法就不能获取到Django后台发送的随机字符串,而是需要利用上面介绍的两种方式获取(页面写上{% csrf_token %},通过隐藏的input标签取value值写在 POST 提交的data数据中;或是从cookie中获取,写在头文件中。)

    使用django框架时:

    • 每次初始化一个项目时都要看看 django.middleware.csrf.CsrfViewMiddleware 这个中间件;
    • 每次在模板里写 form 时都需要加一个 {% csrf_token %} tag ;
    • 每次发 ajax POST 请求,都需要加一个 X_CSRFTOKEN 的 head ;




  • 相关阅读:
    持续交付11-构建和部署的脚本化
    腾讯云即时通讯IM 公共整合
    腾讯云应用生成 UserSig
    「USACO 2020 US Open Platinum」Exercise
    async要点
    jQuery实现textarea高度根据内容自适应
    背景图片设置透明度而不改变内容
    input type=file实现图片上传,预览以及图片删除
    vant 字体图标不显示问题
    vue项目使用mock.js
  • 原文地址:https://www.cnblogs.com/hoyun/p/15683903.html
Copyright © 2020-2023  润新知