• Django中间件及csrf跨站请求处理


    django中间件

    """
    django中间件是django的门户
    1.请求来的时候需要先经过中间件才能到达真正的django后端
    2.响应走的时候最后也需要经过中间件才能发送出去
    
    django自带七个中间件
    """
    django请求生命周期流程图
    
    研究django中间件代码规律
    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',
    ]
    
    class SessionMiddleware(MiddlewareMixin):
        def process_request(self, request):
            session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
            request.session = self.SessionStore(session_key)
        def process_response(self, request, response):
            return response
          
    class CsrfViewMiddleware(MiddlewareMixin):
          def process_request(self, request):
            csrf_token = self._get_token(request)
            if csrf_token is not None:
                # Use same token next time.
                request.META['CSRF_COOKIE'] = csrf_token
        def process_view(self, request, callback, callback_args, callback_kwargs):
            return self._accept(request)
    
        def process_response(self, request, response):
            return response
          
    class AuthenticationMiddleware(MiddlewareMixin):
        def process_request(self, request):
            request.user = SimpleLazyObject(lambda: get_user(request))
    """
    django支持程序员自定义中间件并且暴露给程序员五个可以自定义的方法
        1.必须掌握
            process_request
            
            process_response
        2.了解即可
            process_view
                
            process_template_response
            
            process_exception
    """

    如何自定义中间件

    """
    1.在项目名或者应用名下创建一个任意名称的文件夹
    2.在该文件夹内创建一个任意名称的py文件
    3.在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
        然后在这个类里面就可以自定义五个方法了
        (这五个方法并不是全部都需要书写,用几个写几个)
    4.需要将类的路径以字符串的形式注册到配置文件中才能生效
    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',
        '你自己写的中间件的路径1',
        '你自己写的中间件的路径2',
        '你自己写的中间件的路径3',
    ]
    
    """
    """
    1.必须掌握
            process_request 
                1.请求来的时候需要经过每一个中间件里面的process_request方法
                结果的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
                2.如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
                3.如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行
                而是直接原路返回(校验失败不允许访问...)
                process_request方法就是用来做全局相关的所有限制功能
                
            process_response
                1.响应走的时候需要经过每一个中间件里面的process_response方法
                该方法有两个额外的参数request,response
                2.该方法必须返回一个HttpResponse对象
                    1.默认返回的就是形参response
                    2.你也可以自己返回自己的
                3.顺序是按照配置文件中注册了的中间件从下往上依次经过
                    如果你没有定义的话 直接跳过执行下一个
            
            研究如果在第一个process_request方法就已经返回了HttpResponse对象,那么响应走的时候是经过所有的中间件里面的process_response还是有其他情况
            是其他情况
                就是会直接走同级别的process_reponse返回
            
            flask框架也有一个中间件但是它的规律
                只要返回数据了就必须经过所有中间件里面的类似于process_reponse方法
                
                
    2.了解即可
            process_view
                路由匹配成功之后执行视图函数之前,会自动执行中间件里面的该放法
                顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
                
            process_template_response
                返回的HttpResponse对象有render属性的时候才会触发
                顺序是按照配置文件中注册了的中间件从下往上依次经过
                
            process_exception
                当视图函数中出现异常的情况下触发
                顺序是按照配置文件中注册了的中间件从下往上依次经过
    """

    csrf跨站请求伪造

    """
    钓鱼网站
        我搭建一个跟正规网站一模一样的界面(中国银行)
        用户不小心进入到了我们的网站,用户给某个人打钱
        打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
        但是唯一不同的时候打钱的账户不适用户想要打的账户变成了一个莫名其妙的账户
    
    大学英语四六级
        考之前需要学生自己网站登陆缴费
    
    内部本质
        我们在钓鱼网站的页面 针对对方账户 只给用户提供一个没有name属性的普通input框
        然后我们在内部隐藏一个已经写好name和value的input框
    
    如何规避上述问题
        csrf跨站请求伪造校验
            网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
            当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行    
    """

    如何符合校验

    # form表单如何符合校验
    <form action="" method="post">
        {% csrf_token %}
        <p>username:<input type="text" name="username"></p>
        <p>target_user:<input type="text" name="target_user"></p>
        <p>money:<input type="text" name="money"></p>
        <input type="submit">
    </form>
    
    # ajax如何符合校验
    // 第一种 利用标签查找获取页面上的随机字符串
    {#data:{"username":'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
    // 第二种 利用模版语法提供的快捷书写
    {#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
    // 第三种 通用方式直接拷贝下面的js代码并应用到自己的html页面上即可
    data:{"username":'jason'}
    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相关装饰器

    """
    1.网站整体都不校验csrf,就单单几个视图函数需要校验
    2.网站整体都校验csrf,就单单几个视图函数不校验
    """
    from django.views.decorators.csrf import csrf_protect,csrf_exempt
    from django.utils.decorators import method_decorator
    """
    csrf_protect  需要校验
        针对csrf_protect符合我们之前所学的装饰器的三种玩法
    csrf_exempt   忽视校验
        针对csrf_exempt只能给dispatch方法加才有效
    """
    # @csrf_exempt
    # @csrf_protect
    def transfer(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            target_user = request.POST.get('target_user')
            money = request.POST.get('money')
            print('%s给%s转了%s元'%(username,target_user,money))
        return render(request,'transfer.html')
    
    
    
    from django.views import View
    
    # @method_decorator(csrf_protect,name='post')  # 针对csrf_protect 第二种方式可以
    # @method_decorator(csrf_exempt,name='post')  # 针对csrf_exempt 第二种方式不可以
    @method_decorator(csrf_exempt,name='dispatch')
    class MyCsrfToken(View):
        # @method_decorator(csrf_protect)  # 针对csrf_protect 第三种方式可以
        # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第三种方式可以
        def dispatch(self, request, *args, **kwargs):
            return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)
    
        def get(self,request):
            return HttpResponse('get')
    
        # @method_decorator(csrf_protect)  # 针对csrf_protect 第一种方式可以
        # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第一种方式不可以
        def post(self,request):
            return HttpResponse('post')
    while True: print('studying...')
  • 相关阅读:
    构建之法阅读笔记05
    构建之法阅读笔记04
    构建之法阅读笔记03
    第九周学习进度条
    个人冲刺
    第八周进度条
    Git疑难解决
    Git常用命令
    git配置SSH公钥
    Laravel框架中如何使用 Presenter 模式?
  • 原文地址:https://www.cnblogs.com/xuewei95/p/15725852.html
Copyright © 2020-2023  润新知