Django的安全机制 CSRF 跨站请求访问

跨站请求伪造

一、简介

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

开启此功能后服务端会做两样设置:

  1. 会在cookie中加入 csrftoken字段

  2. 在html模板中 form表单POST请求需加入  {% csrf_token %} 

  注:1. 和2. 生成的字段name和值不一样,但都有效。

全局:

  中间件 django.middleware.csrf.CsrfViewMiddleware

settings.py

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',
]

局部:

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

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

二、应用

1、普通表单

#veiw中设置返回值:
  return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))  
     或者
     return render(request, 'xxx.html', data)
# html中设置Token:
  {% csrf_token %}

  html中设置的{% crsf_token %} 渲染后在from表单中生成隐藏的input标签

<input type="hidden" name="csrfmiddlewaretoken" value="ATvEtmpN8CFuc57eFrnGPjMlIgW2pLQUSKkFAc1FhiSrYbwyI8DuMOv1UubPjxuQ">

  注意:html表单中生成的为token名字为:csrfmiddlewaretoken

 

2、Ajax

  对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。

  view.py

class SessionLogin(View):
    def get(self, request):
        return render(request, 'session_login.html')

    def post(self, request):
        u = request.POST.get('username')
        p = request.POST.get('pwd')
        if u != user.get('username'):
            return render(request, 'session_login.html')
        if p == user.get('password'):
            request.session['current_user'] = u
            request.session.set_expiry(10)
            return redirect('/session_index/')    # form表单提交时可以跳转
            # return HttpResponse('OK') # form表单提交时可以跳转
            # return render(request, 'session_index.html')
        else:
            return render(request, 'session_login.html')

  html中ajax发起POST请求

  关键技术:

       获取:$.cookie('csrftoken')  从cookie中获取csrftoken

       设置:$.ajaxSetup({ beforeSend: function (xhr, settings) {xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'))})  //ajax请求前设置csrftoken

       临时设置:$.ajax({ headers:{'X-CSRFtoken': $.cookie('csrftoken') }}, ...)

    <script>
        //获取cookie
        //正则语法验证是否是(GET|HEAD|OPTIONS|TRACE)中的任何一种方法,是则返回true
        function csrfSafeMethod(method) {
            // these HTTP methods do not require CSRF protection
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }

        function submit() {
            let username = $('#username').val();
            let pwd = $('#pwd').val();
            let data = {'username':username,'pwd':pwd};
            $.ajaxSetup({
                beforeSend: function (xhr, settings) {
                    // 如果HTTP请求Method 非GET|HEAD...等,并且不是跨域请求,则设置'X-CSRFtoken'请求头
                    if(!csrfSafeMethod(settings.type) && !this.crossDomain){
                        xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken'));
                    }
                    //console.log('this', this);
                    //this为当次ajax请求的全部内容实体对象
                    //console.log('settings.type:',settings.type);
                    //settings.type 当次执行请求时的HTTP-Method
                    //console.log('this.crossDomain:',this.crossDomain);
                }
            });

            $.ajax({
                url:'/session_login/',
                data:data,
                type:'POST',
                {#headers:{'X-CSRFtoken': $.cookie('csrftoken') }, //请求时临时加入CSRFtoken#}
                success:function (response_data, textStatus, jqXHR) {
                    {#console.log(textStatus);#}
                    {#console.log(jqXHR.statusText);#}
                    {# window.location.href = '/session_index/';#}
                }
            });
        }
        $('#submit').click(submit)
    </script>

 

 

 

 

  

 

posted on 2020-07-21 16:25  zhangmingda  阅读(230)  评论(0编辑  收藏  举报

导航