zoukankan      html  css  js  c++  java
  • Django中与CSRF相关的内容

    Django中与CSRF相关的内容

    1.什么是CSRF?

    ​ CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。

    2.Django下的CSRF认证机制

    ​ django 第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 csrftoken值,把这个 csrftoken 放在 cookie 里。然后每次请求都带着这个值过来完成校验。

    token字符串的前32位是salt, 后面是加密后的token, 通过salt能解密出唯一的secret。官方文档中说到,检验token时,只比较secret是否和cookie中的secret值一样,

    而不是比较整个token。django会验证表单中的token和cookie中token是否能解出同样的secret,secret一样则本次请求合法,这样就能避免被 CSRF 攻击。

    ​ 例如:在html 中, 为每个post请求的form 表单增加一个 {% csrf_token %} 标签,它的功能其实是给form表单增加一个隐藏的input标签。服务端收到请求后,

    django 会对这个请求的 cookie 里的 csrftoken 字段的值和提交的表单里的 csrfmiddlewaretoken 字段的值进行处理,比较secret是否一样,secret一样则本次请求合法。

    3.具体的实现方法

    django通过中间件 django.middleware.csrf.CsrfViewMiddleware 来防止跨站请求伪造。

    #settings.py
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',#csrf的认证
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    

    3-1 form表单当中附加csrftoken

      #为每个post请求的form 表单增加一个 {% csrf_token %} 标签,如果不添加,post请求的时候你会发现一个 Forbidden的错误
        
        <form action="" method="post" id="loginForm" novalidate="novalidate">
        
        {% csrf_token %}#
        
        <div>
          <input type="text" name="username" class="username" placeholder="用户名" autocomplete="off">
        </div>
        <div>
          <input type="password" name="password" class="password" placeholder="密码" oncontextmenu="return false"
                 onpaste="return false">
        </div>
        <button id="submit" type="submit">登 陆</button>
        <span style="color: red;">{{ error }}</span>
      </form>
    

    3-2 Ajax的post请求设置csrf_token的方式

    方式1:
        通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
        
        data:{
            
            csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(), #form表单里必须写{% csrf_token %}#}
    
        },
    
    方式2:
     data:{
           
            csrfmiddlewaretoken:"{{ csrf_token }}", #form表单里不用写{% csrf_token %}  模板语法替换产生
    
        },
            
    
    #示例:
     <script src="{% static 'jquery.js' %}"></script>
        
        #基于jQuery的实现
        <script>
        	$('#btn').click(function () {
                
                $.ajax({ 
                    
                    url:"{% url 'login' %}", 
                    type:'post' ,
                    data:{	
                        username:$('[name=username]').val(),
                        password:$('[name=password]').val(),
                        
                        csrfmiddlewaretoken:$('[name=csrfmiddlewaretoken]').val(),#form表单里必须写 {% csrf_token %}#}--方式1
                        	#或
                        csrfmiddlewaretoken:"{{ csrf_token }}", #form表单里不用写 {% csrf_token %}--方式2 
                    },
    
                    success:function(res){	
                        var resStr = JOSN.parse(res);
                        console.log(res,typeof res);	
                    }
                })
            })
            
        </script>
    
    方式3:通过获取返回的cookie中的字符串,放置在请求头中发送。
    注意:需要引入一个jquery.cookie.js插件,jquery操作cookie。下载地址 https://plugins.jquery.com/cookie/
        
        jquery.cookie.js基于jquery;先引入jquery,再引入:jquery.cookie.js;
    
    <script src="{% static 'jquery.js' %}"></script>
    <script src="{% static 'jquery.cookie.js' %}"></script>
    
    $.ajax({
        
        url:'/test/',
        type:'post',
    	headers:{"X-CSRFToken":$.cookie('csrftoken')}, #从Cookie取csrftoken,并设置到请求头headers中
    
        #ajax里面的headers参数,自定制请求头,可以将csrf_token加在这里,我们发contenttype类型数据的时候,csrf_token就可以这样加
     
    })
    
    
    注意:
    
      1.如果使用从cookie中取csrftoken的方式,需要确保cookie存在csrftoken值。
    
      2.如果你的视图渲染的HTML文件中没有包含 {% csrf_token %},Django可能不会设置CSRFtoken的cookie。-->不是所有请求都有csrftoken这个cookie键值对
    
      3.这个时候需要使用ensure_csrf_cookie()装饰器强制设置Cookie。
        
    
    django.views.decorators.csrf import ensure_csrf_cookie
    
    @ensure_csrf_cookie  #强制给请求对应的响应添加csrftoken这个cookie键值对
    def login(request):
        pass
    

    3-3 CSRF Token相关装饰器

    from django.views.decorators.csrf import csrf_exempt,csrf_protect
        
      csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置csrfToken全局中间件。
      csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
    
    示例1:   
    #views.py
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    # @csrf_exempt
    @csrf_protect
    def login(request):
        if request.method == 'GET':
            return render(request,'login.html')
        else:
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'zhangsan' and password == '1234':
    
                return HttpResponse('OK')
            else:
                return redirect('login')
            
     #login.html
    <form action="/login/" method="post">
      用户名: <input type="text" name="username">
      密码: <input type="password" name="password">
      <input type="submit">
    </form>
    
    #settings.py
        MIDDLEWARE = [
             'django.middleware.csrf.CsrfViewMiddleware',   
        ]
        
    【1】settings中设置了全局中间件,在login.html中不设置{% csrf_token %},当post提交数据时,Forbidden (403)
    	如果在FBV的函数上使用csrf_exempt装饰器,可以成功提交数据。
        
    【2】settings中没有设置全局中间件,当post提交数据时可以成功提交。如果在FBV的函数上使用csrf_exempt装饰器,Forbidden (403)。
    
    
    
    示例2:注意csrf-token装饰器的特殊性,在CBV模式下它只能加在dispatch上面。
    	 添加装饰器的格式必须为@method_decorator(),括号里面为装饰器的函数名
        
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    
    
    #@method_decorator(csrf_exempt, name='dispatch')
    class HomeView(View):
        
        @method_decorator(csrf_exempt)
        def dispatch(self, request, *args, **kwargs):
            return super(HomeView, self).dispatch(request, *args, **kwargs)
    
        def get(self, request):
            return render(request, "home.html")
    
        def post(self, request):
            print("Home Viw POST method...")
            return redirect("/index/")
    
  • 相关阅读:
    消息中间件(一)MQ详解及四大MQ比较
    SIP协议
    PAT (Basic Level) Practice 1008 数组元素循环右移问题
    LeetCode-Algorithms 1. 两数之和
    PAT (Basic Level) Practice 1040 有几个PAT
    PAT (Basic Level) Practice 1023 组个最小数
    PAT (Basic Level) Practice 1021 个位数统计
    PAT (Basic Level) Practice 1007 素数对猜想
    PAT (Basic Level) Practice 1006 换个格式输出整数
    PAT (Basic Level) Practice 1004 成绩排名
  • 原文地址:https://www.cnblogs.com/xiaomage666/p/11312682.html
Copyright © 2011-2022 走看看