Django之csrf跨站请求
CSRF_TOKEN跨站请求伪造
介绍:浅谈CSRF(Cross-site request forgery)跨站请求伪造
在form表单中应用:
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password"></p>
<p><input type="submit"></p>
</form>
在Ajax中应用:
放在data里:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="/static/jquery-3.3.1.js"></script>
<title>Title</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password" id="pwd"></p>
<p><input type="submit"></p>
</form>
<button class="btn">点我</button>
</body>
<script>
$(".btn").click(function () {
$.ajax({
url: '',
type: 'post',
data: {
'name': $('[name="name"]').val(),
'password': $("#pwd").val(),
'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
},
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
使用django官方提供的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');
// 每一次都这么写太麻烦了,可以使用$.ajaxSetup()方法为ajax请求统一设置。
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);
}
}
});
将下面的文件配置到你的Django项目的静态文件中,在html页面上通过导入该文件即可自动帮我们解决ajax提交post数据时校验csrf_token的问题,(导入该配置文件之前,需要先导入jQuery,因为这个配置文件内的内容是基于jQuery来实现的)
更多细节详见:Djagno官方文档中关于CSRF的内容
放在cookie里:
获取cookie:document.cookie
是一个字符串,可以自己用js切割,也可以用jquery的插件
获取cookie:$.cookie(‘csrftoken’)
设置cookie:$.cookie(‘key’,’value’)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="/static/jquery-3.3.1.js"></script>
<script src="/static/jquery.cookie.js"></script>
<title>Title</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password" id="pwd"></p>
<p><input type="submit"></p>
</form>
<button class="btn">点我</button>
</body>
<script>
$(".btn").click(function () {
var token=$.cookie('csrftoken')
//var token='{{ csrf_token }}'
$.ajax({
url: '',
headers:{'X-CSRFToken':token},
type: 'post',
data: {
'name': $('[name="name"]').val(),
'password': $("#pwd").val(),
},
success: function (data) {
console.log(data)
}
})
})
</script>
</html>
关于CSRF中间件的全站禁用和局部禁用
当我们知道csrf的作用和使用方式后,我们联系实际情况考虑到实际应用中会出现下列情况:
- 整个django项目都校验csrf 但是某些个视图函数\类不想校验
- 整个django项目都不校验csrf 但是某些个视图函数\类需要校验
全站禁用:注释掉中间件 ‘django.middleware.csrf.CsrfViewMiddleware’,
局部禁用:用装饰器(在FBV中使用)
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 不再检测,局部禁用(前提是全站使用)
# @csrf_exempt
# 检测,局部使用(前提是全站禁用)
# @csrf_protect
def csrf_token(request):
if request.method=='POST':
print(request.POST)
return HttpResponse('ok')
return render(request,'csrf_token.html')
在CBV中使用:
# CBV中使用
from django.views import View
from django.views.decorators.csrf import csrf_exempt,csrf_protect
from django.utils.decorators import method_decorator
# CBV的csrf装饰器,只能加载类上(指定方法为dispatch)和dispatch方法上(django的bug)
# 给get方法使用csrf_token检测
@method_decorator(csrf_exempt,name='dispatch')
class Foo(View):
def get(self,request):
pass
def post(self,request):
pass
CBV添加装饰器的方式(与正常情况不一样 需要注意)
主要有三种方式
# @method_decorator(csrf_protect, name='post') # 方式2:单独生效
class MyView(views.View):
@method_decorator(csrf_protect) # 方式3:整个类中生效
这里需要会去看CBV的源码剖析,CBV源码内起作用的也是dispaly,通过反射执行字符串表示的功能,因此第三种方式是整个类中生效的。
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
# @method_decorator(csrf_protect) # 方式1:单独生效
def post(self, request):
return HttpResponse('from cbv post view')
注意有一个装饰器是特例只能有一种添加方式>>>:csrf_exempt
只有在dispatch方法处添加才会生效