Django中间件之csrf跨站请求伪造
csrf跨站请求伪造
CSRF(Cross Site Request Forgery) 跨站请求伪造。也被称为One Click Attack和Session Riding,通常缩写为CSRF或XSRF。如果从名字你还不不知道它表示什么,你可以这样理解:攻击者(黑客,钓鱼网站)盗用了你的身份,以你的名义发送恶意请求,这些请求包括发送邮件、发送消息、盗取账号、购买商品、银行转账,从而使你的个人隐私泄露和财产损失。
CSRF攻击实例
听了这么多,可能大家还云里雾里,光听概念可能大家对于CSRF还是不够了解,下面我将举一个例子来让大家对CSRF有一个更深层次的理解。
# 以钓鱼网站为例:
我搭建一个跟正规网站一模一样的界面(中国银行)
用户不小心进入到了我们的网站,用户给某个人打钱
打钱的操作确确实实是提交给了中国银行的系统,用户的钱也确确实实减少了
但是唯一不同的时候打钱的账户不是用户想要打的账户变成了一个莫名其妙的匿名账户
# 内部本质
我们在钓鱼网站的页面 针对对方账户 只给用户提供一个没有name属性的普通input框
然后我们在内部隐藏一个已经写好name和value的input框
那么我们在提交的时候只向后端提交存在name属性和value值得input框内容
此时隐藏得input框得name和value属性值是固定得,相当于'诈骗'账户
示例:
8000端口:html
<h1>我是正真得网站</h1>
<form action="" method="post">
<p>username: <input type="text" name="username"></p>
<p>target_user: <input type="text" name="target_user"></p>
<p>money: <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
8001端口:html
<h1>我是钓鱼网站</h1>
<form action="http://127.0.0.1:8000/transfer/" method="post">
<p>username: <input type="text" name="username"></p>
<p>target_user: <input type="text"></p>
<input type="text" name="target_user" value="gary" style="display: none">
<p>money: <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
需要将钓鱼网站的端口号修改,不然冲突
display:none可以隐藏某个元素,且隐藏的元素不会占用任何空间。也就是说,该元素不但被隐藏了,而且该元素原本占用的空间也会从页面布局中消失。
如何避免上述问题呢:
# csrf跨站请求伪造校验
网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
当这个页面朝后端发送post请求的时候 我的后端会先校验唯一标识,如果唯一标识不对直接拒绝(403 forbbiden)如果成功则正常执行
form如何符合校验
前提:
'django.middleware.csrf.CsrfViewMiddleware', # 需要去配置文件将csrf中间件打开
# 只需要在form表单内添加:{% csrf_token %}
<h1>我是正真得网站</h1>
<form action="" method="post">
{% csrf_token %}
<p>username: <input type="text" name="username"></p>
<p>target_user: <input type="text" name="target_user"></p>
<p>money: <input type="text" name="money"></p>
<p><input type="submit"></p>
</form>
ajax如何符合校验
# 除了form表单可以提交post请求之外,ajax也是可以提交post请求的
# 那么上述方法只是针对form表单的,那么我们接下来来研究ajax是如何
方式一:
// 第一种 利用标签查找获取页面上的随机字符串
<script>
$('#d1').click(function (){
$.ajax({
url:'',
type:'post',
data:{'username':$('[name=username]').val(),'target_user':$('[name=target_user]').val(),'money':$('[name=money]').val(),'csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},
// 主动取出csrfmiddlewaretoken对应的值发送给后端
success:function (){
}
})
})
</script>
方式二:
# 利用模版语法提供的快捷书写 (如果是前后端分离的项目,就不方便使用该方法)
data:{'username':$('[name=username]').val(),'target_user':$('[name=target_user]').val(),'money':$('[name=money]').val(),'csrfmiddlewaretoken':{{ csrf_token }},
方式三:
// 第三种 通用方式直接拷贝js代码并应用到自己的html页面上即可
{% load static %}
<script src="{% static 'js/mycsrf.js' %}"></script>
data:{'username':$('[name=username]').val(),'target_user':$('[name=target_user]').val(),'money':$('[name=money]').val()},
配置文件:
// 需手动创建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相关装饰器
需求:
1.网站整体都不校验csrf,就单单几个视图函数校验
2.网站整体都校验csrf,就单单几个不视图函数不校验
# 这里django给我们提供了现成的两个装饰器供我们使用
1. csrf_protect 需要校验
2. csrf_exempt 忽视校验
csrf_exempt
忽视校验:
csrf_protect
需要校验
研究CBV添加装饰器是否可行:
from django.views import View
# @method_decorator(csrf_protect,name='post') # 针对csrf_protect 第二种方式可以
# @method_decorator(csrf_exempt,name='post') # 针对csrf_exempt 第二种方式不可以
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrfToken(View):
# @method_decorator(csrf_protect) # 针对csrf_protect 第三种方式可以
# @method_decorator(csrf_exempt) # 针对csrf_exempt 第三种方式可以
def dispatch(self, request, *args, **kwargs):
return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)
def get(self,request):
return HttpResponse('get')
# @method_decorator(csrf_protect) # 针对csrf_protect 第一种方式可以
# @method_decorator(csrf_exempt) # 针对csrf_exempt 第一种方式不可以
def post(self,request):
return HttpResponse('post')
总结:
针对csrf_protect:需要校验
三种方式都可行。
针对csrf_exempt:忽视校验
只有给dispatch方法添加才可行
(可以在dispatch方法紧上方添加装饰器,
也可以使用@method_decorator(csrf_exempt,name='dispatch')在类上方添加装饰器)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)