13. Django高级之中间件、csrf跨站请求伪造


Django中间件

什么是中间件?

Middleware is a framework of hooks into Django’s request/response processing.
It’s a light, low-level “plugin” system for globally altering Django’s input or output.

  官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

  但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

  说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。

"https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
class="col-md-6 col-md-offset-3">
class="panel panel-primary">
class="panel-heading">
class="panel-body">

class="text-center">登录

"" method="post"> {% csrf_token %}

用户名:"text" name="username" class="form-control">

密码:"password" name="password" class="form-control">

"submit" class="btn btn-primary btn-block">

"color: red">{{ error_msg }}

前端 login.html 前端 login.html
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect
# 自定义访问控制中间件
class LoginMiddleware(MiddlewareMixin):
    def process_request(self, request):
        # 如果不是路径不是login就会一直重定向
        if not request.path == '/login/':
            # 接着去获取登录状态
            is_login = request.session.get('is_login')
            # 如果没有登录,重定向到登录页面(如果登录了就会直接往下走)
            if not is_login:
                return redirect('/login')
            
# 自定义登录日志中间件
from app01 import models
class LoginLogMiddlewareMixin(MiddlewareMixin):
    def process_request(self, request):
        name = request.session.get('name',None)
        # name有值或为空都记录日志
        # 客户端的IP 地址
        ip = request.META['REMOTE_ADDR']
        # 客户端的user-agent 字符串
        user_agent = request.environ['HTTP_USER_AGENT']
        models.Log.objects.create(name=name, ip=ip, user_agent=user_agent)            

自定义 Middleware.py
自定义 Middleware.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'app01.middleware.LoginMiddleware',
    'app01.middleware.LoginLogMiddlewareMixin'
]

配置文件 settings.py
配置文件 settings.py
# 创建日志记录表
class Log(models.Model):
    name = models.CharField(max_length=32,null=True,verbose_name='用户名')
    ip = models.CharField(max_length=32,verbose_name='ip地址')
    user_agent = models.CharField(max_length=32,verbose_name='客户端类型')
    visit_time = models.DateTimeField(auto_now_add=True,verbose_name='登录时间')
    
# 不要忘了执行数据库迁移两条命令哦

模板层models.py
模板层models.py

CSRF_TOKEN跨站请求伪造

https://www.cnblogs.com/liuqingzheng/p/9505044.html
    
1 CSRF或者XSRF:跨站请求伪造
2 攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的但是却完成了攻击者所期望的一个操作,
比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。
如下:其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户 3 防范:CSRF攻击防范 Referer:上一次访问的地址(图片防盗链) https://www.lagou.com/gongsi/ - 在请求地址中添加 token 并验证 - 在 HTTP 头中自定义属性并验证 - 把随机字符串放在请求体中

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  1.登录受信任网站A,并在本地生成Cookie。

  2.在不登出A的情况下,访问危险网站B。

看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:

  1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。

  2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)

  3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。

django中处理csrf

1 中间件不要注释了
2 如果是form表单
{% csrf_token %}

给谁转:

转多少:

3 如果是ajax提交:两种方案 $.ajax({ url: '/transfer/', method: 'post', //data: {to_user: $('#id_name').val(), money: $('#id_money').val(),csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val()}, data: {to_user: $('#id_name').val(), money: $('#id_money').val(),csrfmiddlewaretoken:'{{csrf_token}}'}, success: function (data) { console.log(data) } })

cookie的处理

获取cookie:document.cookie

是一个字符串,可以自己用js切割,也可以用jquery的插件

获取cookie:$.cookie(‘csrftoken’)

设置cookie:$.cookie(‘key’,’value’)




    
    <script src="/static/jquery-3.3.1.js"></script>
    <script src="/static/jquery.cookie.js"></script> //用jquery的插件
    Title


{% csrf_token %}

用户名:

密码:

<script> $(".btn").click(function () { var token=$.cookie('csrftoken') // 获取 $.ajax({ url: '', headers:{'X-CSRFToken':token}, type: 'post', data: { 'name': $('[name="name"]').val(), 'password': $("#pwd").val(), }, success: function (data) { console.log(data) } }) }) </script>

csrf放到请求头中

 $.ajax({
            url: '',
            headers:{'X-CSRFToken':token},
            type: 'post',
            data: {
                'name': $('[name="name"]').val(),
                'password': $("#pwd").val(),
            },
            success: function (data) {
                console.log(data)
            }

        })

全局使用csrf,局部视图函数禁用csrf

1 在视图函数上加装饰器
from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 不再检测,局部禁用(前提是全站使用)
# @csrf_exempt
# 检测,局部使用(前提是全站禁用)
@csrf_protect
def csrf_token(request):
  if request.method=='POST':
        print(request.POST)

        return HttpResponse('ok')
    return render(request,'csrf_token.html')

总结

1 中间件:request对象,response
    -process_request
        -返回None,继续往下走
        -返回response对象,直接返回
    -process_response
        -处理response
    -定义一个类,继承MiddlewareMixin
    -配置文件配置(执行顺序)
2 中间件能干什么
    -全局的登陆认证
    -记录日志(访问日志,登录日志,客户端类型。。。)
    -对ip地址进行限制(一分钟访问十次)
    
3 csrf,xsrf:跨站请求伪造
    
4 django中处理csrf攻击
    1 form表单形式  {% csrf_token %}
    2 ajax提交:手动传,2种方式
    3 ajax提交:放到请求头中
       $.ajax({
            url: '/transfer/',
            headers:{'X-CSRFToken':'sssssss','name':'lqz'},
            method: 'post',
            data: {to_user: $('#id_name').val(), money: $('#id_money').val(),csrfmiddlewaretoken:'{{csrf_token}}'},
            success: function (data) {
                console.log(data)

            }
        })
        
        
4 请求头中的数据,django如何获取
    request.META.get('HTTP_字段名大写')

5 django的csrf中间件
 -全局使用csrf,中间件解开
    -局部禁用:在视图函数上加一个装饰器csrf_exempt
    -全局禁用,中间件加注释
    -局部使用:在视图函数上加一个装饰器csrf_protect

django启动流程

1  配置文件中指定WSGI_APPLICATION = 'day60.wsgi.application'

2  被wsgi服务器管理,一旦有请求进来,会触发application()

3  实际触发WSGIHandler类的__call__传入environ, start_response

4  把environ包装成request对象,执行中间件,执行路由,执行视图函数,返回response

5  最终结束django