第十篇:跨站请求伪造csrf
Posted cnhyk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十篇:跨站请求伪造csrf相关的知识,希望对你有一定的参考价值。
钓鱼网站
钓鱼网站和正规网站的页面一模一样,提交网页数据的url也一样,但是会在页面中设置隐藏属性的form表单。例如转账:给用户书写的form表单,对方账号的input没有name属性,然后另外写一个具有默认的并且是隐藏的具有name属性的input框。
form表单如何通过csrf校验
为了防止此类事情的发生,我们使用csrf_token生成随机字符串
在form表单内添加:
{% csrf_token %}
browser客户端向服务端发动get请求,服务端返回给browser一串随机的字符串,当browser向服务端发送post请求时,会携带上该字符串,服务端会先对该随机字符串进行校验,如果客户端携带的字符串和服务器上的字符串一致,服务端会允许客户端提交post请求,否则会被forbidden掉。
当客户端向django服务端发送post请求,django中间件django.middleware.csrf.CsrfViewMiddleware
会获取post中携带的name为“csrfmiddlewaretoken
”的value是否和之前返回给客户端的value一致。
ajax如何通过csrf校验
第一种:自己手动获取
<body>
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="username"></p>
<p>密码: <input type="text" name="password"></p>
<p><button id="d1">发送ajax请求</button></p>
</form>
<script>
$('#d1').click(function () {
$.ajax({
url: '',
type: 'post',
data: {'username': 'jason', 'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val()},
success: function (data) {
alert(data)
}
})
})
</script>
</body>
</html>
第二种:利用模板语法,获取到随机字符串
<body>
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="username"></p>
<p>密码: <input type="text" name="password"></p>
<p><button id="d1">发送ajax请求</button></p>
</form>
<script>
$('#d1').click(function () {
$.ajax({
url: '',
type: 'post',
data: {'username': 'jason', 'csrfmiddlewaretoken': '{{ csrf_token }}'},
success: function (data) {
alert(data)
}
})
})
</script>
</body>
</html>
第三种:通用方式,引用外部js文件,此种方法是django官网推荐的
在static文件夹下新建一个js文件(eg:myset.py)
// static/myset.py
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的js文件
<body>
<form action="" method="post">
{% csrf_token %}
<p>用户名:<input type="text" name="username"></p>
<p>密码: <input type="text" name="password"></p>
<p><button id="d1">发送ajax请求</button></p>
</form>
<!--此处引入csrf文件-->
{% load static %}
<script src="{% static 'myset.js' %}"></script>
<script>
$('#d1').click(function () {
$.ajax({
url: '',
type: 'post',
data: {'username': 'jason''},
success: function (data) {
alert(data)
}
})
})
</script>
</body>
</html>
# csrf相关装饰器
可以局部对csrf的校验进行更改
针对FBV
针对FBV的视图方法:
首先需要导入包:
# views.py
from django.views.decorators.csrf import csrf_exempt, csrf_protect
局部不校验csrf
当我们网站整体都检验csrf的时候,我们可以让某几个视图函数不校验,需要使用csrf_exempt模块:
# views.py
@csrf_exempt # 不校验被装饰的函数
def func(request):
pass
局部校验csrf
当我们网站整体都不校验csrf的时候,我们可以让某几个视图函数校验,需要使用csrf_protect模块:
# views.py
@csrf_protect # 校验被装饰函数
def func(request):
pass
针对CBV
针对CBV的视图方法:
针对下面的CBV的方法,我们如何做到局部修改csrf校验呢?
# views.py
from django.views import View
class MyHome(View):
def get(self, request):
return HttpResponse('get')
def post(self, request):
return HttpResponse('post')
局部校验csrf
全局不校验,单单针对局部的CBV的方法进行校验:
第一种方法:直接装饰在CBV内部的函数之上
# views.py
# 需要导入模块
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
class MyHome(View):
def get(self, request):
return HttpResponse('get')
@method_decorator(csrf_protect) # 使CBV中的函数被校验csrf
def post(self, request):
return HttpResponse('post')
第二种方法:装饰在CBV类上,指定装饰CBV类中的哪个函数
# views.py
# 需要导入模块
from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator
@method_decorator(csrf_protect, name='post') # 指名道姓的给CBV中的函数装饰
class MyHome(View):
def get(self, request):
return HttpResponse('get')
def post(self, request):
return HttpResponse('post')
局部不校验csrf
全局校验,单单针对局部的CBV中的方法不校验:
第一种方法:直接装饰在CBV内部的函数之上
# views.py
# 需要导入模块
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
class MyHome(View):
def get(self, request):
return HttpResponse('get')
@method_decorator(csrf_exempt) # 使CBV中函数不被校验csrf
def post(self, request):
return HttpResponse('post')
第二种方式:装饰在CBV类上,指定装饰CBV类中的哪个函数
# views.py
# 需要导入模块
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt, name='post') # 指名道姓的给CBV中的函数装饰
class MyHome(View):
def get(self, request):
return HttpResponse('get')
def post(self, request):
return HttpResponse('post')
给CBV中的所有函数加装饰器
我们之前看源码,发现在匹配CBV中类的方法的时候,统一由dispatch函数分发,因此我们可以重写父类中的dispatch方法,给dispatch方法加装饰器,再return出去。
这种方式,相当于对CBV中的所有函数都装饰上了,影响的是CBV中的所有函数。
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
# @method_decorator(csrf_exempt, name='post') # csrf_exempt 第二种方式不行
@method_decorator(csrf_exempt, name='dispatch') # 可以!!!
class MyHome(View): # APIView
# @method_decorator(csrf_protect) # 第三种 类中所有的方法都装
# @method_decorator(csrf_exempt) # csrf_exempt 第三种方式可以
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request,*args,**kwargs)
def get(self,request):
return HttpResponse('get')
# @method_decorator(csrf_protect) # 第一种方式
# @method_decorator(csrf_exempt) # csrf_exempt 第一种方式不行
def post(self,request):
return HttpResponse('post')
特例:对于CBV来说,当我们打开全局校验csrf的时候,针对CBV中的某个方法不进行校验的时候,这个csrf_exempt只能给dispatch方法装饰(在CBV中想要使用局部不校验,只能装饰在重写父类的dispatch函数上)。
以上是关于第十篇:跨站请求伪造csrf的主要内容,如果未能解决你的问题,请参考以下文章