1.知识储备
1 django解决了csrf攻击,中间件: django.middleware.csrf.CsrfViewMiddleware '''
内部实现:
向浏览器发POST请求时,每次请求都会在模板里隐藏content ,会默认返回一个csrf k:v 的值(k时csrf,v是随机字符串 可以在process_request里面取出,再根据k取出v进行校验),这个值会隐藏在页面中,
下次发请求时一定要带着这个隐藏的字符串,如果不想携带就报403 Forbidden禁止访问(黑客拿不到这个随机字符串,并且串有失效时间防止黑客破解拿出)
'''
2 后期中间件不能注释,每次发送post请求,都需要携带csrf_token随机字符串 -form表单提交 -在form表单中 {% csrf_token%} '''
{{csrf_token}} #变量,不能用这个
{% csrf_token %} #标签,使用这个
''' -ajax提交(如何携带) 方式一:放到data中 (***推荐) $.ajax({ url: '/csrf_test/', method: 'post', data: {'name': $('[name="name"]').val(), 'password': $('[name="password"]').val(), 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val() }, success: function (data) { console.log('成功了') console.log(data) }, error: function (data) { console.log('xxxxx') console.log(data) } }) 方式二:放到data中 'csrfmiddlewaretoken':'{{ csrf_token }}' 方式三:放到头中 headers:{'X-CSRFToken':'{{csrf_token}}'}, # jquery.cookie.js -在浏览器中对cookie进行增,删,查,改 -前后端分离(js操作cookie) # 全局使用,局部禁csrf -在视图函数上加装饰器 from django.views.decorators.csrf import csrf_exempt,csrf_protect # 全局启用,局部禁用(中间件不能注释,这个视图函数,已经没有csrf校验了) @csrf_exempt #加上这个装饰器 def csrf_test(request): if request.method=='GET': return render(request,'csrf_test.html') else: name=request.POST.get('name') password=request.POST.get('password') print(name) print(password) return HttpResponse('登录成功') # 全局禁用,局部使用csrf @csrf_protect #加上这个装饰器 def csrf_test(request): if request.method=='GET': return render(request,'csrf_test.html') else: name=request.POST.get('name') password=request.POST.get('password') print(name) print(password) return HttpResponse('登录成功') # 古怪的使用方式,在urls.py中 path('csrf_test/', csrf_exempt(views.csrf_test))
2.模拟银行转账中出现的csrf攻击
settings.py
MIDDLEWARE = [ ... 'django.middleware.csrf.CsrfViewMiddleware', ... ]
urls.py
from django.urls import path from app01 import views from django.views.decorators.csrf import csrf_exempt urlpatterns = [ path('', views.index), path('transfer/', views.transfer), path('csrf_test/', views.csrf_test), ]
views.py
from django.shortcuts import render,HttpResponse,redirect def login_auth(func): def inner(request, *args, **kwargs): # 登录校验 name = request.session.get('name') if name: res = func(request, *args, **kwargs) return res else: path = request.get_full_path() return redirect('/login/?returnUrl=%s' % path) return inner ### session版登录 def login(request): if request.method == 'GET': return render(request, 'login.html') else: name = request.POST.get('name') password = request.POST.get('password') if name == 'lqz' and password == '123': # 写入session # 登录成功,重定向 request.session['name']=name path = request.GET.get('returnUrl') if path: obj = redirect(path) else: obj = redirect('/index/') return obj else: return HttpResponse('用户名或密码错误') @login_auth def index(request): return render(request,'index.html') @login_auth def transfer(request): # /transfer/?from=lqz&to=egon&total=100 f=request.GET.get('from') t=request.GET.get('to') total=request.GET.get('total') print('转账成功') return HttpResponse('转账成功') def csrf_test(request): if request.method=='GET': return render(request,'csrf_test.html') else: name=request.POST.get('name') password=request.POST.get('password') print(name) print(password) return HttpResponse('登录成功')
csrf_test.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script> <title>Title</title> </head> <body> {% csrf_token %} <form action="" method="post"> <p>用户名<input type="text" name="name"></p> <p>密码<input type="password" name="password"></p> <p><input type="submit" value="提交" id="submit"></p> </form>
</body> </html>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>银行正版网站</title> </head> <body> <a href="/transfer/?from=lqz&to=egon&total=100">点我,给egon转100块钱</a> </body> </html>