钓鱼网站
钓鱼网站和正规网站的页面一模一样,提交网页数据的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函数上)。
来源:https://www.cnblogs.com/cnhyk/p/12274325.html