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发送到后台,后台也不需要做任务修改

原文地址:https://www.cnblogs.com/lixiang1013/p/7821940.html