• 21)django-csrf(跨站请求伪造)


    一:目录

      1)简介及无CSRF时存在隐患

      2)csrf原理

      3)csrf 设置

      4)Form提交(CSRF)

      5)Ajax提交(CSRF)
        CSRF请求头 X-CSRFToken

    二:csrf简介 

      csrf主要是为了防止跨站请求伪造(XSS攻击别人可以提交运行JS代码)

      django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。

      而对于django中设置防跨站请求伪造功能有分为全局和局部。

      全局:

        中间件 django.middleware.csrf.CsrfViewMiddleware

      局部:

      •   @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
      •   @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

      注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

    二:csrf原理

          客户端发请求,如果是第一次过来,比如GET,我不仅把数据数据你,还给一串加密串,只我自己能反解。

       你下一次过来提交数据的时候,你要带这串来,这样我才允许,不然允许提交数据。


          这个一般体现在那里?如果你往后台发POST请求,你把CSRF禁掉话,会报403名错误了。

        django做了一层防护,GET不会有影响,POST的时候会在来你发过来的请求你找那个随机字符串。

        但是我们没有这个字符串。所以禁止。

        我们可以在页面form请求加一
            {{csrf_token}}生成随机串 这个就是CSRF的token.这样显示是没有用的。

      在form里{%csrf_token%}后台才能拿到token 这是django csft原理

         比如:别人的网站写JS代码,但是提交了我们的网站,如果没有开启csrf他就直接提交过来了,并运行了代码,这是很危险的。

      如果开吂CSRF。别人的网站没有随机token.他就不能提交代码到我们的网站。

    三:csrf设置  

     

        settings:
         'django.middleware.csrf.CsrfViewMiddleware',
    
        form表单
    
        <form action="/login/" method="post">
            {% csrf_token %} <!--post提供token给后台-->
            <input type="text" name="username">
            <input type="text" name="password">
            <input type="checkbox" value="1" name="rmb">免登录10秒
            <input type="submit" name="+">
        </form>

      # {% csrf_token %}不仅在页面中生成,在cookie中也有生成.如图所示

      

      

    四:form提交数据

      上面的提交需要csft_token传入到后台。我们有两种方式提交。第一种:普通submit,;第二种ajax提交。ajax也要带token,这能提交数据到后台

      普通submit提交,只需要在form里设置

     {% csrf_token %}

      提交POST后页面和cookie效果,会生成token:

       <form action="/login/" method="post">
            <input type='hidden' name='csrfmiddlewaretoken' value='GGO5hq95CfY3PrbGU2wep1WOpbMZOYNJ02QunbqKQOmeh1ShXNC1IIiTbut1Yij2' />
            <input type="text" name="username">
            <input type="text" name="password">
            <input type="checkbox" value="1" name="rmb">免登录10秒
            <input type="submit" name="+">
        </form>
    </body>
    </html>
    
      浏览器cookie Request Cookies
    212 Hm_lpvt_407473d433e871de861cf818aa1405a1 1510386206 N/A N/A N/A 53 Hm_lvt_407473d433e871de861cf818aa1405a1 1509847957,1509936833,1509966824,1510386206 N/A N/A N/A 85 csrftoken 4MGKIn5K2p8K3hYkPKPagY0akHpjieqZo8I9O8mpgYwVvRFVSvVXzFmf606lsyWi N/A N/A N/A 74 Response Cookies 139 csrftoken 4MGKIn5K2p8K3hYkPKPagY0akHpjieqZo8I9O8mpgYwVvRFVSvVXzFmf606lsyWi / 364.0 days 139

    五:ajax提交  

    AJAX只要把csrftoken拿过来,放在请求头发过去就行了
    django里token的KEY是什么:X-CSRFtoke
       from django.conf import settings
    
        print(settings.CSRF_HEADER_NAME)===>HTTP_X_CSRFTOKEN(jdango会在前面加HTTP_)==>X-CSRFtoken(请求头不能加下划线)
    
        按django规范来写就是X-CSRFtoken

      ajax提交两种方法:

      1)在ajax里提交headers:{"X-CSRFtoken":csrftoken},但是如果提交ajax非常多的时候就不方便,可以设置全局提交。

      

    <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            $("#btn").click(
                    function(){
                        //获取token
                        var csrftoken=$.cookie("csrftoken")
    
                        $.ajax({
                            url:"/login/",
                            type:"POST",
                            //token放在请求头
                            headers:{"X-CSRFtoken":csrftoken},
                            data:{"username":"root","password":123},
                            success:function(data){
    
                            }
    
                        })
            })
        </script>
      2)全文提交
        #方式2
    <!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="username">
            <input type="text" name="password">
            <input type="checkbox" value="1" name="rmb">免登录10秒
            <input type="submit" name="+">
            <input id="btn" type="button" value="增加">
        </form>
        <script src="/static/jquery-1.12.4.js"></script>
        <script src="/static/jquery.cookie.js"></script>
        <script>
            $("#btn").click(
                    function(){
                            //这就是发ajax请求
    {#                    obj=XMLHttpRequest()#}
    {#                    obj.open()#}
    {#                    obj.send()#}
                        //可以对整个页面所有的ajax请求做配置
                        //方式2
                        $.ajaxSetup({
                            //表示在发送ajax请求之前执行,这是全局中配置,比如下面有好多个ajax  请求
                            beforeSend:function(xhr,settings){
                                //xhr表示XML HTTP requst对象,所有AJAZ操作
                                xhr.setRequestHeader("X-CSRFtoken",$.cookie("csrftoken"))
                            }
                        })
                         //获取token
    {#                    var csrftoken=$.cookie("csrftoken")#}
    
                        $.ajax({
                            url:"/login/",
                            type:"POST",
                            //token放在请求头
                            //方式1
    {#                        headers:{"X-CSRFtoken":$.cookie("csrftoken")#}
                            data:{"username":"root","password":123},
                            success:function(data){
    
                            }
    
                        })
            })
        </script>
    </body>
    </html>

      3)其他问题

      A)

        #现在是全局都加了token,如果有几个就不需要token验证,如何处理? 给不需要验证的请求加@csrf_exempt装饰器
        @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
        @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
        注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
    

       B)GET是不需要提交token认证的,所以修改如下

    #上面POST和GET都是token验证,其实GET是不需要token的,如何处理?
        <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        {% csrf_token %}
      
        <input type="button" onclick="Do();"  value="Do it"/>
      
        <script src="/static/plugin/jquery/jquery-1.8.0.js"></script>
        <script src="/static/plugin/jquery/jquery.cookie.js"></script>
        <script type="text/javascript">
            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 Do(){
      
                $.ajax({
                    url:"/app01/test/",
                    data:{id:1},
                    type:'POST',
                    success:function(data){
                        console.log(data);
                    }
                });
      
            }
        </script>
    </body>
    </html>

      总结:

      1)csrf主要是在settings里面设置,这个设置是全局的,特别设置可以使用@csrf_protect装饰器,即使全局中没有开启csrf验证,也要求验证。@csrf_exempt装饰器,可以要求不需要验证

      2)在页面form设置{% csrf_token %}

      3) 普通提交,后台不需要做任务修改

      4)ajax提交,需要把token发送到后台,后台也不需要做任务修改

  • 相关阅读:
    Ubuntu下快速建立跨多个平台的cocos2d-x项目
    转盘抽奖效果练习
    javascript网页弹出层练习
    PHP中Terminal提示不是内部或外部命令,也不是可运行的程序问题解决
    网页授权获取用户信息(自我总结)
    用easywechat开发微信支付功能以及红包接口调用注意事项
    微信公众平台开发步骤(包括自定义菜单、网页授权、分享功能)
    laravel-wechat 配置安装
    第1讲 html介绍 html运行原理
    总结学习方向
  • 原文地址:https://www.cnblogs.com/lixiang1013/p/7821940.html
Copyright © 2020-2023  润新知