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) 编辑 收藏 举报