cookie与session补充与中间件与CSRF


目录
  • django操作cookie补充
  • django操作session
  • CBV添加装饰器
  • django中间件
  • 自定义中间件
    • 必会的方法
    • 了解的方法
  • CSRF跨站请求伪造
  • CSRF解决策略

django操作cookie补充

set_signed_cookie(key,value,...):设置cookie

res = HttpResponse()
res.set_signed_cookie(key, value, salt='', max_age=,...)

参数说明:

  • key:cookie的键
  • value:cookie的值
  • salt:加盐处理(在cookie的值后加上一些干扰项)
  • max_age:超时时间,默认单位秒,超过时间删除cookie
  • expires:专门针对IE浏览器设置超时时间

delete_cookie(key):删除指定cookie

res = HttpResponse()
res.delete_cookie(key)

django操作session

django操作session需要用到一张表来保存session,在我们使用django数据库迁移命令会产生一堆默认的表,其中就有一张django_session表,这张表就是django用来保存session的。

设置session:

request.session['key'] = value

可以设置多个键值对,表中只用一条记录来保存。

设置session过程:

  1. 产生一个随机字符串;
  2. 表中存储随机字符串与加密数据的对应关系;
  3. 将产生的随机字符串发送给客户端并让其保存;

获取session:

request.session.get('key')

获取session过程:

  1. 自动获取客户端请求中cookie的随机字符串;
  2. 自动去存储session数据的表中比对;
  3. 如果比对成功自动获取并'解密'返回;

浏览器中保存的值:

服务器中保存的:

django默认的session失效时间是14天。

其他方法补充

session操作 作用
request.session.session_key 获取产生的随机字符串
request.session.delete() 删除所有seesion
request.session.flush() 与delete()类似
request.session.set_expiry(value) 设置失效时间
value为整数,单位为秒
value为0,浏览器关闭就失效
value为dateime或timedelta,则指定时间失效
value为None,依赖全局失效策略
request.session.keys() 获取session所有键
request.session.values() 获取session所有值
request.session.items() 获取session所有键值对

CBV添加装饰器

如果想要给CBV添加装饰器需要借助一个专门的装饰器模块:method_decorator

导入:

from django.utils.decorators import method_decorator

方式一:直接在类中的某个方法上添加

class MyCBV(views.View):
    @method_decorator(装饰器名称)
    def get(self, request):
        return HttpResponse("from CBV get view")

方式二:直接在类上添加,并指定内部方法

@method_decorator(装饰器名称,name='get')
@method_decorator(装饰器名称,name='post')
class MyCBV(views.View):
    def get(self, request):
        return HttpResponse("from CBV get view")
    def post(self, request):
        return HttpResponse("from CBV post view")

方式三:重写dispatch方法并添加装饰器,这会作用于类中所有的方法

class MyCBV(views.View):
    @method_decorator(装饰器名称)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

django中间件

django的请求生命周期流程中,从wsgiref网关接口到路由层需要经过一个中间件,django自带七个中间件,每个都有各自对应的功能,进入settings.py配置文件就可以看到这七个中间件。

除了这七个中间件,django还支持自定义中间件并提供五个可以自定义的方法:process_request、process_response、process_view、process_template_response、process_excepton,它们分别会在不同的时期执行。

自定义中间件

在我们编写自定义中间件时,需要进行如下操作:

  1. 在应用下创建一个任意名称的文件夹
  2. 在该文件夹内创建一个任意名称的py文件
  3. 在该py文件内编写中间件类
  4. 编写完后要在配置文件中注册

比如我在应用名app01下先创建文件夹middleware,然后在文件夹下创建middle.py,最后在py文件中创建中间件类MyMiddle,这个注册就是这么写:

MIDDLEWARE = [
    七个自带中间件,
    # 自定义中间件注册
    'app01.middleware.middle.MyMiddle'
]

必会的方法

1.process_request

客户端发送请求时,会从上往下依次执行配置文件中注册了的中间件里面的process_request方法,如果没有则直接跳过。

如果该方法自己返回了HttpResponse对象,那么请求不再继续往后直接返回相应的数据,也就是说浏览器就会直接接收该方法返回的HttpResponse对象,不在执行视图函数代码。

from django.shortcuts import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class MyMiddle(MiddlewareMixin):
    def process_request(self, request):
        return HttpResponse('from MyMiddle process_request')

这个方法可以用于校验用户是否在黑名单之中之类的事务。

2.process_response

服务端响应客户端时,会从下往上依次执行配置文件中注册了的中间件里面的process_response方法,如果没有则直接跳过。

如果该方法自己返回了HttpResponse对象,那么响应会替换成该HttpResponse对象数据,而不再是视图函数想要返回给客户端的数据。

from django.shortcuts import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class MyMiddle(MiddlewareMixin):
    # response就是视图函数返回给客户端的数据
    def process_response(self, request, response):
        return HttpResponse('from MyMiddle process_request')

了解的方法

1.process_view

路由匹配成功之后,执行视图函数之前,从上往下执行配置文件中注册了的中间件里面的process_view方法。

如果该方法自己返回了HttpResponse对象,那么不再执行视图函数,而是直接返回给浏览器。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddle(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        print('视图函数:', view_func)
        print('视图函数位置参数', view_args)
        print('视图函数关键字参数', view_kwargs)
        return HttpResponse('from MyMiddle process_view')

2.process_template_response

视图函数执行完毕之后返回的对象中的render属性对应一个函数方法,则会从下往上执行配置文件中注册了的中间件里面的process_template_response方法。

视图函数:

def index(request):
    res = HttpResponse()
    def abc():
        return HttpResponse('abc')
    res.render = abc
    return res

中间件:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddle(MiddlewareMixin):
    def process_template_response(self, request, response):
        return response

3.process_exception

视图函数执行过程中报错并在返回响应的时,会从下往上执行配置文件中注册了的中间件里面的process_exception。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddle(MiddlewareMixin):
    def process_exception(self, request, exception):
        print('异常:',exception)
        return HttpResponse('报错了')

CSRF跨站请求伪造

CSRF跨站请求伪造,简单地说,就是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。

比如说攻击者建立了一个盗版页面,用户在这个盗版页面上输入信息后提交,这个盗版页面会向正版页面的服务器发送请求以实现一些操作,因为用户曾经在正版页面登录过,正版页面认证过这个用户,所以不会阻拦这个用户的请求。

或者说此时有一个正版页面是转账页面,这时攻击者也造了一个盗版页面模仿正版页面,用户如果在盗版页面输入收账用户时,用户输入的收账用户是无效的,因为真实的收账用户被隐藏了,用户一旦提交转账后,就会给被隐藏的收账用户转钱。

正版网站

home.html




    
    Title


我是正规的网站

当前账户:

目标账户:

转账金额:

views:

def home(request):
    if request.method == 'POST':
        current_user = request.POST.get('current_user')
        target_user = request.POST.get('target_user')
        money = request.POST.get('money')
        return HttpResponse(f'{current_user} 给 {target_user} 转了{money}')
    return render(request, 'home.html')

盗版网站

home.html:form表单是向正版网站发送的请求




    
    Title


我是盗版的网站

当前账户:

目标账户:

转账金额:

views

def home(request):
    return render(request, 'home.html')

CSRF解决策略

首先我们先确保如下红框内的中间件存在

解决方法一:表单使用模板语法{% csrf_token %}

然后再正版页面的表单中加上一行模板语法{% csrf_token %}

{% csrf_token %}

当前账户:

目标账户:

转账金额:

此时的正版页面就会多了一个隐藏的input标签,这个标签就可以用来标识页面。这时候盗版页面就无法向正版服务器发送请求了,或者说发送请求时被拒绝了。

解决方法二:ajax使用模板语法{% csrf_token %}

html




    
    Title
    


我是正规的网站

{% csrf_token %}

当前账户:

目标账户:

转账金额:

ajax携带数据:

'csrfmiddlewaretoken':$('input[name="csrfmiddlewaretoken"]').val()

还可以这么写:

'csrfmiddlewaretoken':{{ csrf_token }}

解决方法三:引入js文件

引人以下js:只适用于ajax提交,引入后ajax无需携带解决方法二里的csrfmiddlewaretoken数据。

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);
    }
  }
});