• 第十篇:跨站请求伪造csrf


    钓鱼网站

    钓鱼网站和正规网站的页面一模一样,提交网页数据的url也一样,但是会在页面中设置隐藏属性的form表单。例如转账:给用户书写的form表单,对方账号的input没有name属性,然后另外写一个具有默认的并且是隐藏的具有name属性的input框。

    form表单如何通过csrf校验

    为了防止此类事情的发生,我们使用csrf_token生成随机字符串

    在form表单内添加:

    {% csrf_token %}
    

    browser客户端向服务端发动get请求,服务端返回给browser一串随机的字符串,当browser向服务端发送post请求时,会携带上该字符串,服务端会先对该随机字符串进行校验,如果客户端携带的字符串和服务器上的字符串一致,服务端会允许客户端提交post请求,否则会被forbidden掉。

    当客户端向django服务端发送post请求,django中间件django.middleware.csrf.CsrfViewMiddleware会获取post中携带的name为“csrfmiddlewaretoken”的value是否和之前返回给客户端的value一致。

    ajax如何通过csrf校验

    第一种:自己手动获取

    <body>
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="username"></p>
        <p>密码: <input type="text" name="password"></p>
        <p><button id="d1">发送ajax请求</button></p>
    </form>
     
    <script>
        $('#d1').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'username': 'jason', 'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val()},
                success: function (data) {
                    alert(data)
                }
            })
     
        })
    </script>
    </body>
    </html>
    

    第二种:利用模板语法,获取到随机字符串

    <body>
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="username"></p>
        <p>密码: <input type="text" name="password"></p>
        <p><button id="d1">发送ajax请求</button></p>
    </form>
     
    <script>
        $('#d1').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'username': 'jason', 'csrfmiddlewaretoken': '{{ csrf_token }}'},
                success: function (data) {
                    alert(data)
                }
            })
     
        })
    </script>
    </body>
    </html>
    

    第三种:通用方式,引用外部js文件,此种方法是django官网推荐的

    在static文件夹下新建一个js文件(eg:myset.py)

    // static/myset.py
     
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('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);
        }
      }
    });
    

    使用方法:引入csrf的js文件

    <body>
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="username"></p>
        <p>密码: <input type="text" name="password"></p>
        <p><button id="d1">发送ajax请求</button></p>
    </form>
     
    <!--此处引入csrf文件-->
    {% load static %}
    <script src="{% static 'myset.js' %}"></script>
    <script>
        $('#d1').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'username': 'jason''},
                success: function (data) {
                    alert(data)
                }
            })
     
        })
    </script>
    </body>
    </html>
    

    csrf相关装饰器

    可以局部对csrf的校验进行更改

    针对FBV

    针对FBV的视图方法:

    首先需要导入包:

    # views.py
     
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    

    局部不校验csrf

    当我们网站整体都检验csrf的时候,我们可以让某几个视图函数不校验,需要使用csrf_exempt模块:

    # views.py
     
    @csrf_exempt  # 不校验被装饰的函数
    def func(request):
        pass
    

    局部校验csrf

    当我们网站整体都不校验csrf的时候,我们可以让某几个视图函数校验,需要使用csrf_protect模块:

    # views.py
     
    @csrf_protect  # 校验被装饰函数
    def func(request):
        pass
    

    针对CBV

    针对CBV的视图方法:

    针对下面的CBV的方法,我们如何做到局部修改csrf校验呢?

    # views.py
     
    from django.views import View
    class MyHome(View):
        def get(self, request):
            return HttpResponse('get')
     
        def post(self, request):
            return HttpResponse('post')
    

    局部校验csrf

    全局不校验,单单针对局部的CBV的方法进行校验:

    第一种方法:直接装饰在CBV内部的函数之上

    # views.py
     
    # 需要导入模块
    from django.views.decorators.csrf import csrf_protect
    from django.utils.decorators import method_decorator
     
    class MyHome(View):
     
        def get(self, request):
            return HttpResponse('get')
     
        @method_decorator(csrf_protect)  # 使CBV中的函数被校验csrf
        def post(self, request):
            return HttpResponse('post')
    

    第二种方法:装饰在CBV类上,指定装饰CBV类中的哪个函数

    # views.py
     
    # 需要导入模块
    from django.views.decorators.csrf import csrf_protect
    from django.utils.decorators import method_decorator
     
    @method_decorator(csrf_protect, name='post')  # 指名道姓的给CBV中的函数装饰
    class MyHome(View):
        def get(self, request):
            return HttpResponse('get')
     
        def post(self, request):
            return HttpResponse('post')
    

    局部不校验csrf

    全局校验,单单针对局部的CBV中的方法不校验:

    第一种方法:直接装饰在CBV内部的函数之上

    # views.py
     
    # 需要导入模块
    from django.views.decorators.csrf import csrf_exempt
    from django.utils.decorators import method_decorator
     
    class MyHome(View):
     
        def get(self, request):
            return HttpResponse('get')
     
        @method_decorator(csrf_exempt)  # 使CBV中函数不被校验csrf
        def post(self, request):
            return HttpResponse('post')
    

    第二种方式:装饰在CBV类上,指定装饰CBV类中的哪个函数

    # views.py
     
    # 需要导入模块
    from django.views.decorators.csrf import csrf_exempt
    from django.utils.decorators import method_decorator
     
    @method_decorator(csrf_exempt, name='post')  # 指名道姓的给CBV中的函数装饰
    class MyHome(View):
        def get(self, request):
            return HttpResponse('get')
     
        def post(self, request):
            return HttpResponse('post')
    

    给CBV中的所有函数加装饰器

    我们之前看源码,发现在匹配CBV中类的方法的时候,统一由dispatch函数分发,因此我们可以重写父类中的dispatch方法,给dispatch方法加装饰器,再return出去。

    这种方式,相当于对CBV中的所有函数都装饰上了,影响的是CBV中的所有函数。

    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
     
     
    # @method_decorator(csrf_exempt, name='post')  # csrf_exempt 第二种方式不行
    @method_decorator(csrf_exempt, name='dispatch')  # 可以!!!
    class MyHome(View):  # APIView
        # @method_decorator(csrf_protect)  # 第三种 类中所有的方法都装
        # @method_decorator(csrf_exempt)  # csrf_exempt 第三种方式可以
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request,*args,**kwargs)
     
        def get(self,request):
            return HttpResponse('get')
        # @method_decorator(csrf_protect)  # 第一种方式
        # @method_decorator(csrf_exempt)  # csrf_exempt 第一种方式不行
        def post(self,request):
            return HttpResponse('post')
    

    特例:对于CBV来说,当我们打开全局校验csrf的时候,针对CBV中的某个方法不进行校验的时候,这个csrf_exempt只能给dispatch方法装饰(在CBV中想要使用局部不校验,只能装饰在重写父类的dispatch函数上)。

  • 相关阅读:
    python map 详解
    python 中的集合(set) 详解
    python中的列表(list) 切片详解
    django 创建数据库表 命令
    django如何检查创建的模型(model)是否有语法错误或者逻辑错误
    python 列表(list)去除重复的元素总结
    python中的 zip函数详解
    django post和get 比较
    正则表达式的特殊符号和字符详细解析
    .NET/MVC-发布到IIS6.1提示未能加载程序集System.Web.Http.WebHost
  • 原文地址:https://www.cnblogs.com/cnhyk/p/12274325.html
Copyright © 2020-2023  润新知