• 跨站请求伪造(csrf)


    跨站请求伪造(csrf)

    一、钓鱼网站

    什么是xxx
    为什么要有xxx
    如何使用xxx

    钓鱼网站:就类似于你搭建了一个跟银行一模一样的web页面, 用户在你的网站转账的时候输入用户名 密码 对方账户, 银行里面的钱确实少了 但是发现收款人变了

    原理: 你写的form表单中 用户的用户名 密码都会真实的提交给银行后台, 但是收款人的账户却不是用户填的 你暴露给用户的是一个没有name属性的input框,你自己提前写好了一个隐藏的带有name和value的input框

    解决钓鱼网站的策略: 只要是用户想要提交post请求的页面 我在返回给用户的时候就提前设置好一个随机字符串, 当用户提交post请求的时候 我会自动先取查找是否有该随机字符串 , 如果有 正常提交, 如果没有 直接报403

    二、csrf

    2.1 在form表单中实现

    在form表单中添加: {% csrf_token %}

    <!--login.html-->
    <body>
    <form action="" method="post">
        {% csrf_token %}
        <p>
            用户: <input type="text" name="username">
        </p>
        <p>
            密码: <input type="password" name="password">
        </p>
        <p>
            <input type="submit" value="提交">
        </p>
    </form>
    

    页面展示

    img

    对应的中间件:django.middleware.csrf.CsrfViewMiddleware

    # 对应的中间件
    'django.middleware.csrf.CsrfViewMiddleware',
    
    

    2.2 AJAX请求实现

    方式一:

    <!--login.html-->
    <body>
    <form action="" method="post">
        {% csrf_token %}
    	<!--通过js找到这个隐藏的框-->
    </form>
    <button id="b1">发ajax</button>
    <script>
        $('#b1').click(function () {
            $.ajax({
                url: "",
                type: "post",
                // 第一种方式
                data: {
                    "username": "randy",
                    "password": 123,
                    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用JQuery取出csrfmiddlewaretoken的值,拼接到data中
                },
                {#data:{'username':'randy','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
                {#data:{'username':'randy'},#}
                success: function (data) {
                    alert(data)
                }
            })
        })
    </script>
    

    方式二:

    <button id="b1">发ajax</button>
    
    {#<script src="/static/setup.js"></script>#}
    <script>
        $('#b1').click(function () {
            $.ajax({
                url:"",
                type:"post",
                // 第二种方式
                data:{'username':'randy','csrfmiddlewaretoken':'{{ csrf_token }}'},         
                success:function (data) {
                    alert(data)
                }
            })
        })
    </script>
    

    方式三(引入js):

    # stupe.js
    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);
        }
      }
    });
    
    <!--login.html-->
    <script src="/static/setup.js"></script>
    <script>
        $('#b1').click(function () {
            $.ajax({
                url:"",
                type:"post",
                // 第三种方式           
                data:{'username':'randy'},
                success:function (data) {
                    alert(data)
                }
            })
        })
    </script>
    

    三、装饰器实现(csrf)

    <body>
    <form action="crsf_cbv" method="post">
        {#        {% csrf_token %}#}
        <p>
            用户: <input type="text" name="username">
        </p>
        <p>
            密码: <input type="password" name="password">
    
        </p>
        <p>
            <input type="submit" value="提交">
        </p>
    
    </form>
    </body>
    
    MIDDLEWARE = [   
     'django.middleware.security.SecurityMiddleware',  
     'django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',  
     # 'app.mymiddleware.my_middleware.M1',    
     # 'app.mymiddleware.my_middleware.M2',
     ]
    

    3.1 csrf_exempt不进行校验

    # urls.py
    from app import views
    urlpatterns = [   
        url(r'^exem/', views.exem),
    ]
    
    # views.py
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    @csrf_exempt
    def exem(request):
        """前端不需要csrf字符串验证 {% csrf_token %} """
        return HttpResponse("exempt不进行校验")
    

    img

    3.2 csrf_protect进行校验

    # urls.py
    from app import views
    urlpatterns = [   
        url(r'^protect/', views.protect),
    ]
    
    # views.py
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    @csrf_protect
    def protect(request):
        """"""前端需要 csrf 字符串验证{% csrf_token %} """"""
        return HttpResponse("protect 校验")
    

    img

    3.3 给CBV添加csrf校验装饰器

    <body>
    <form action="crsf_cbv" method="post">
        {#        {% csrf_token %}#}
        <p>
            用户: <input type="text" name="username">
        </p>
        <p>
            密码: <input type="password" name="password">
    
        </p>
        <p>
            <input type="submit" value="提交">
        </p>
    
    </form>
    </body>
    

    不需要验证

    # urls.py
    urlpatterns = [
        url(r'^crsf_cbv/', views.MyCrsfCbv.as_view()),
    ]
    
    # views.py
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    from django.views import View
    # post不验证不需要csrf字符串
    class MyCrsfCbv(View):
        def get(self, request):
            return HttpResponse('hahaha')
    
        def post(self, request):
            return HttpResponse('post')
    

    结果post

    需要验证

    方式一:

    # urls.py
    urlpatterns = [
        url(r'^crsf_cbv/', views.MyCrsfCbv.as_view()),
    ]
    
    # views.py
    # 导入模块
    # method_decorator(装饰器,方法名)
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    
    from django.views import View
    # 第一种方式验证,改变装饰第一个参数进行验证或不验证
    
    # cbv装csrf_exempt装饰器,只能给dispatch添加校验
    # @method_decorator(csrf_exempt,name='dispatch')
    
    # cbv装csrf_protect,指明道姓的给谁添加校验csrf,name=get/post
    @method_decorator(csrf_protect, name='post')
    class MyCrsfCbv(View):
        def get(self, request):
            return HttpResponse('hahaha')
    
        @method_decorator(csrf_protect) # 有无
        def post(self, request):
            return HttpResponse('post')
    

    方式二:

    # urls.py
    urlpatterns = [
        url(r'^crsf_cbv/', views.MyCrsfCbv.as_view()),
    ]
    
    # views.py
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    from django.views import View
    
    class MyCrsfCbv(View):
         # 第二种
        # @method_decorator(csrf_exempt) # 不进行csrf校验
        @method_decorator(csrf_protect) # 进行csrf校验
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request, *args, **kwargs)
        
        def get(self, request):
            return HttpResponse('hahaha')
    
        def post(self, request):
            return HttpResponse('post')
    

    总结:

    1. 在给CBV装饰的时候有区别

      • 需要导入一个固定的装饰器 method_decorator(装饰器,方法名)

      • csrf_exempt这个装饰器比较特殊 装饰的时候 只能给dispatch方法装

    2. 其他的装饰器 自定义的 模块的

      • 直接类外面指名道姓的装
      • 给dispatch装
      • 直接装在方法上
    在当下的阶段,必将由程序员来主导,甚至比以往更甚。
  • 相关阅读:
    动态规划算法
    Spring依赖循环
    使用JMH微基准测试
    expect介绍和使用
    autossh使用(本机记住ssh密码)
    ssh端口转发(ssh隧道)
    WSL2中的Centos8安装桌面
    Tmux Plugin Manager使用及具体插件
    Python使用os.chdir命令切换python工作目录
    python脚本要控制jenkins触发job
  • 原文地址:https://www.cnblogs.com/randysun/p/11773996.html
Copyright © 2020-2023  润新知