跨站请求伪造和csrf_token使用
之前我们在写项目时会把下面项目setting.py中的 这一句注释掉:
'django.middleware.csrf.CsrfViewMiddleware',
如果不注释这一句我们在输入正确用户名和密码的情况下进行如下POST请求时会出错:
浏览器会禁止我们提交,这里就涉及到CSRF
什么是CSRF ? 跨站请求伪造, 问题: 1. 钓鱼网站的页面和正经网站的页面对浏览器来说有什么区别? (页面是怎么来的?) 钓鱼网站的页面是由 钓鱼网站的服务端给你返回的 正经网站的网页是由 正经网站的服务端给你返回的
当注释掉那一句:
遇到钓鱼网站时会出现下面的情况:
其中正经的网站的html
<h1>正经的网站</h1> <form action="/transfer/" method="post"><p> 转出: <input type="text" name="from"> </p> <p> 转入: <input type="text" name="to"> </p> <p> 金额: <input type="text" name="money"> </p> <p> <input type="submit" value="转账"> </p> </form>
钓鱼的网站的html
<h1>钓鱼的网站</h1> <form action="http://127.0.0.1:8002/transfer/" method="post"> <p> 转出: <input type="text" name="from"> </p> <p> 转入: <input type="text" name=""> <input type="text" name="to" style="display: none" value="哪吒"> </p> <p> 金额: <input type="text" name="money"> </p> <p> <input type="submit" value="转账"> </p> </form>
解决办法:
当正经的网站给你返回一个页面的时候,偷偷的在你form表单中塞一个特殊的字符串,后端会记下这个字符串,当你发POST请求时候,后端会
从你提交的数据里面拿到那个特殊的字符串然后和存的字符串比对一下,如果能比对上就表示你这个请求是来自我这个正经网站的请求,但钓鱼
网站就没有这个特殊的字符串,正经的网站就不会处理这个POST请求。
Django中内置了一个专门处理csrf问题的中间件 django.middleware.csrf.CsrfViewMiddleware 这个中间件做的事情: 1. 在render返回页面的时候,在页面中塞了一个隐藏的input标签 用法: 我们在页面上 form表单 里面 写上 {% csrf_token %} <input type="hidden" name="csrfmiddlewaretoken" value="8gthvLKulM7pqulNl2q3u46v1oEbKG7BSwg6qsHBv4zf0zj0UcbQmpbAdijqyhfE"> 2. 当你提交POST数据的时候,它帮你做校验,如果校验不通过就拒绝这次请求
正经的网站代码修改如下:
<h1>正经的网站</h1> <form action="/transfer/" method="post"> {% csrf_token %} <p> 转出: <input type="text" name="from"> </p> <p> 转入: <input type="text" name="to"> </p> <p> 金额: <input type="text" name="money"> </p> <p> <input type="submit" value="转账"> </p> </form>
然后取消那一句注释:
再次进入正经的网站就会出现:
而且每次刷新的时候value值都不一样
在两个网站上再次进行POST请求时:
以上所用相关代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.shortcuts import render, redirect, HttpResponse # Create your views here. # def login(request): # if request.method == "POST": # # 取出数据 # user = request.POST.get("username") # pwd = request.POST.get("pwd") # # if user == "alex" and pwd =="dsb": # return redirect("http://www.luffycity.com") # # return render(request, "login.html") # 转账 def transfer(request): if request.method == "POST": from_ = request.POST.get("from") to_ = request.POST.get("to") money = request.POST.get("money") print("{} 给 {} 转了 {}钱".format(from_, to_, money)) return HttpResponse("转账成功!") return render(request, "transfer.html")
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>正经的网站</h1> <form action="/transfer/" method="post"> {% csrf_token %} <p> 转出: <input type="text" name="from"> </p> <p> 转入: <input type="text" name="to"> </p> <p> 金额: <input type="text" name="money"> </p> <p> <input type="submit" value="转账"> </p> </form> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>钓鱼的网站</h1> <form action="http://127.0.0.1:8002/transfer/" method="post"> <p> 转出: <input type="text" name="from"> </p> <p> 转入: <input type="text" name=""> <input type="text" name="to" style="display: none" value="哪吒"> </p> <p> 金额: <input type="text" name="money"> </p> <p> <input type="submit" value="转账"> </p> </form> </body> </html>