Djiango:csrf跨站请求伪造
一、csrf跨站请求伪造
1.csrf简介
CSRF跨站点请求伪造Cross Site Request Forgery,是一种挟持用户在当前已登录的web应用程序上执意非本意的操作的攻击方法。
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。
2.模拟钓鱼网站案例
某个钓鱼网站,从网址到页面都和真银行网站一摸一样,当你想要通过银行操作业务的时候,他会将你的银行卡号和密码发送给真的银行,但是转账人取被改成洗钱的账户(隐藏的input
框)提交给银行,然后通过真银行将钱转走。
- 后端
def transfer_func(request):
if request.method == "POST":
username = request.POST.get('username')
transfer_name = request.POST.get('transfer_name')
money = request.POST.get('money')
print(f"{username}给{transfer_name}转账了{money}元")
return render(request, 'transferPage.html')
-
钓鱼网站前端
通过内部隐藏标签,将用户想要转账的转账人更改
二、csrf相关校验策略
在settings中解开注释,开启csrf验证机制,当我们提交POST请求时,在提交数据的位置添加唯一标识,以供后续校验使用
1.form的csrf策略
在form表单内部添加模版语法
{% csrf_token %}
在web浏览器的页面上则会多一个input标签出来,属性name="csrfmiddlewaretoken"
,value
为随机字符串
2.ajax请求csrf策略
(1)方式1:自己手动取值,较为繁琐
在data中添加一个键值对为'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()
$('.c1').click(function (){
$.ajax({
url:'',
type:'post',
data:{
'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val(),
'username':'duoduo',
'transfer_name':'qiuqiu',
'money':11111,
},
success:function (args){
}
})
})
(2)方式2:利用模版语法自动获取(一定要用引号引起来)
在data中添加一个'csrfmiddlewaretoken':'{{ csrf_token }
,自动传一个token
$('.c1').click(function (){
$.ajax({
url:'',
type:'post',
data:{
'csrfmiddlewaretoken':'{{ csrf_token }}',
'username':'duoduo',
'transfer_name':'qiuqiu',
'money':11111,
},
success:function (args){
}
})
})
(3)方式3:直接引入一个js脚步(官网提供的)
通过静态文件,为所有ajax
发送请求时自动添加上csrftoken
及其随机字符串。
在static
中新建一个js文件,将脚本拷贝进去,并在网页上连接进去
参考:https://www.cnblogs.com/Dominic-Ji/p/9234099.html
- csrf.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);
}
}
});
三、csrf相关视图验证
需求:整个django项目都校验csrf,但是某些视图函数/类不校验csrf。
解决:使用csrf提供的装饰器
1.FBV添加csrf校验装饰器
在视图中,为某个函数单独设置需要csrf
校验,或者取消单独某个函数的csrf
校验。
需要导入以下两个模块。
from django.views.decorators.csrf import csrf_protect # 单独校验
from django.views.decorators.csrf import csrf_exempt # 取消校验
-
@csrf_exempt
当添加exempt装饰器时,就算在settings中还保存着csrf校验,该函数对应的路由地址也不会开启csrf校验
@csrf_exempt
def transfer_func(request):pass
-
@csrf_protect
添加protect装饰器,则会开启csrf校验
@csrf_protect
def transfer_func(request):pass
2.CBV添加csrf校验装饰器
当我们和FBV一样添加相同的装饰器给类中的函数的时候,并不会直接报错csrf验证,而是没有cookies。
所以,不能直接给在CBV中的方法添加装饰器,需要导入一个模块,通过该模块的装饰器,给CBV中的方法添加csrf校验功能
# 使用CBV的模块,CBV需要继承该类
from django.views import View
# 添加csrf装饰器的模块
from django.utils.decorators import method_decorator
(1)方式1:单独生效,针对某个方法添加csrf装饰器
class ...():
@method_decorator(csrf_protect)
def post():
(2)方式2:单独生效
给类中的某一个方法添加装饰器
@method_decorator(csrf_protect, name='post')
class MyView(View):
def post(self, request):
return HttpResponse('这里是 MyView 的post')
(3)方式3:给整个类中生效
重写dispatch方法,dispatch是整个CBV方法分发的入口
class MyView(View):
@method_decorator(csrf_protect) # 方式3:重写dispatch方法,为整个类中的方法添加csrf校验
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def post(self, request):
return HttpResponse('这里是 MyView 的post')
特例:csrf_exempt只有第三种方法生效,其他的不方法不支持