csrf跨站请求伪造,csrf校验策略,相关装饰器
钓鱼网站:
模仿一个正规的网站,让用户在该网站上做操作,但是操作的结果会影响到用户正常的网站账户,其中有一些猫腻。
eg:英语四六级考试需要网上先缴费,但是你会发现卡里的钱扣了但是却交到了一个莫名其妙的账户,并不是真正的四六级官方账户。
真假网站的代码区别:
urls.py
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), # 转账接口 path('transfer/',views.transfer_func), ]
viwes.py
from django.shortcuts import render def transfer_func(request): if request.method == 'POST': username = request.POST.get('username') target_name = request.POST.get('target_name') money = request.POST.get('money') print(f"{username}给{target_name}转了{money}元") return render(request,'transferPage.html')
效果展示
当我们输入同样的用户信息,提交之后得到的结果却是不一样的
打印结果
真网站:
假网站:
思考:如何区分真假网站页面发送的请求
CSRF是什么?
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
CSRF可以做什么?
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。
在提交数据的位置添加唯一标识 。
我们之前在发送POST请求时是将settings.py中的这条中间件注掉的,当我们把它打开之后,是无法直接发送POST请求的,添加唯一标识之后就可以正常发送了。
1.form表单操作csrf策略
form表单内部添加 {% csrf_token %}
2.ajax请求csrf策略
方式1: 通过获取隐藏的input标签中的csrfmiddlewaretoken值,放置在data中发送。
自己动手取值,较为繁琐,不推荐使用
$.ajax({
url: "/cookie_ajax/",
type: "POST",
data: {
"username": "Tonny",
"password": 123456,
"csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() // 使用JQuery取出csrfmiddlewaretoken的值,拼接到data中
},
success: function (data) {
console.log(data);
}
})
方式2: 通过获取返回的cookie中的字符串,放置在请求头中发送。
注意:需要引入一个jquery.cookie.js插件。
利用模板语法自动获取(一定要用引号引起来)
$.ajax({
url: "/cookie_ajax/",
type: "POST",
headers: {"X-CSRFToken": $.cookie('csrftoken')}, // 从Cookie取csrf_token,并设置ajax请求头
data: {"username": "Q1mi", "password": 123456},
success: function (data) {
console.log(data);
}
})
方式3:直接引入一个js脚本即可(官网提供的)
参考:https://www.cnblogs.com/Dominic-Ji/p/9234099.html
# 直接使用JS脚本 拓展性最高 <script src="/static/csrf.js"></script> 这里我们把下方代码写到一个js文件中然后使用的时候在网页中导入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); } } });
将上面的文件配置到你的Django项目的静态文件中,在html页面上通过导入该文件即可自动帮我们解决ajax提交post数据时校验csrf_token的问题,(导入该配置文件之前,需要先导入jQuery,因为这个配置文件内的内容是基于jQuery来实现的)。
更多细节详见:Djagno官方文档中关于CSRF的内容
当我们知道csrf的作用和使用方式后,我们联系实际情况考虑到实际应用中会出现下列情况:
- 整个django项目都校验csrf,但是某些个视图函数\类不想校验
- 整个django项目都不校验csrf ,但是某些个视图函数\类需要校验
根据FBV和CBV的分类,导入时候有所区别:
FBV添加装饰器的方式(与正常函数添加装饰器一致)
from django.views.decorators.csrf import csrf_exempt, csrf_protect # @csrf_exempt 想让csrf校验检测就使用装饰器@csrf_protect,不想让csrf校验检测就使用@csrf_exempt @csrf_protect def transfer_func(request):pass
CBV添加装饰器的方式(与正常情况不一样,需要注意)
主要有三种方式
# @method_decorator(csrf_protect, name='post') # 方式2:写在类的上方,单独生效,给类里面的post方法添加装饰器 class MyView(views.View): '''这里需要会去看CBV的源码剖析,CBV源码内起作用的也是dispaly,通过反射执行字符串表示的功能,因此第三种方式是整个类中生效的。''' @method_decorator(csrf_protect) # 方式3:整个类中生效 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方法处添加才会生效