csrf(跨站请求伪造)
什么是csrf:
跨站请求伪造
就是一个钓鱼网站,界面操作和真是的页面一模一样,当用户操作转账功能的时候,转账数据也会发送到真实的后台,但是其中用户输入的信息中对端账户可能会被修改掉,导致用户确实转账了,但是钱却转给了别人。
如何区分钓鱼网站和正经网站?在正经网站返回页面的时候,在form表单中偷偷塞一个特殊的字符串,后端记下该页面对应的字符串的值,等用户发post请求来的时候,我先去校验特殊的字符串是否匹配
如何去写这个特殊的字符串呢?模版语法有一个固定的写法{% csrf_token %},必须写在form表单内
浏览器查看改标签的值,并且每次都在刷新。再来演示刚刚转账的示例
# 正常网站: #views # Create your views here. def transfer(request): if request.method=='POST': username=request.POST.get('username') to_username=request.POST.get('to_username') monery=request.POST.get('monery') print(username,to_username,monery) return render(request,'transfer.html')
<body> <h1>正经网站</h1> <form action="" method="post"> <p>账户名:<input type="text" name="username"></p> <p>对方账户:<input type="text" name="to_username"></p> <p>转账金额:<input type="text" name="monery"></p> <input type="submit"> </form> </body>
# 不正常网站 #views: def transfer(request): return render(request,'transfer.html')
<body> <h1>钓鱼网站</h1> <form action="http://127.0.0.1:8000/transfer/" method="post"> <p>账户名:<input type="text" name="username"></p> <p>对方账户:<input type="text"></p> <p>转账金额:<input type="text" name=monery></p> <input type="text" name="to_username" value="yzn" style="display: none" > # 定义一个隐藏标签 <input type="submit"> </form> </body>
实现效果:
在正常网站前端输入信息正常打印:
在不正常的网站前端输入信息:
在正常网站后端查看打印信息:
怎么解决出现这样的钓鱼网站避免后台接收到虚假网站的数据直接处理出现了csrf
在settings.py文件中把之前注释的内容取消注释
django.middleware.csrf.CsrfViewMiddleware
在前端设置一个csfr_token
<form action="" method="post"> {% csrf_token %} <p>账户名:<input type="text" name="username"></p> <p>对方账户:<input type="text" name="to_username"></p> <p>转账金额:<input type="text" name="monery"></p> <input type="submit"> </form>
查看前端页面会随机产生一个token值,页面刷新就会差生新的token值
前端ajax避免前端出现csrf验证问题:
<button>ajax</button> <script> $('button').click(function () { $.ajax({ url:'', type:'post', data:{'name':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()}, success:function (data) { console.log(data) } }) })
局部不需要csrf效验
# viess.py
from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def index(request): return HttpResponse('ok')
# transfer.html <h1>正经网站</h1> <form action="/index/" method="post"> {# {% csrf_token %}#} #禁用csrf_token <p>账户名:<input type="text" name="username"></p> <p>对方账户:<input type="text" name="to_username"></p> <p>转账金额:<input type="text" name="monery"></p> <input type="submit"> </form>
结果可以访问到OK;全局启用,局部禁用
全局禁用,局部启用
@csrf_protect def index(request): return HttpResponse('ok')
# CBV比较特殊,不能单独加在某个方法上 # 只能加在类上或dispatch方法上 from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt,csrf_protect @method_decorator(csrf_exempt,name='dispatch') # 第一种不行 class Csrf_Token(View): @method_decorator(csrf_exempt) # 第二种可以,全局的 def dispatch(self,request,*args,**kwargs): res = super().dispatch(request,*args,**kwargs) return res @method_decorator(csrf_exempt) # 这里这么写不行!!! def get(self,request): pass def post(self,request): pass