session原理流程、中间件以及csrf攻击

一、django的session原理流程

二、中间件

1、什么是中间件
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能
2、中间件的作用
如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。
Django默认的中间件:(在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图)

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',
]

每一个中间件都有具体的功能

三、自定义中间件

1、中间件的几个方法

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',
]

2、process_request和process_response(全局请求和响应)
process_request:所有请求来了都会经过它(尽量加判断),如果返回HttpResponse对象,将不再继续往前走
当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者
** process_request的作用**:频率限制(限制某个ip地址,一分钟只能几次)、登陆认证(只要没登陆,重定向到login路径)、记录用户访问日志(ip、时间、访问路径)
process_response的作用:统一给所有(某几个路径)加cookie、统一给所有(某几个路径)加响应头
3、自定义中间件
-写一个类,继承MiddlewareMixin
-里面写方法process_request(请求来了,一定会触发它的执行)、process_response(请求走了,一定会触发它的执行)
--在setting中配置(注意,放在前和放在后)

        MIDDLEWARE = [
            ...
            'app01.mymiddle.MyMiddleware1',
            ...
        ]

例如:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class MyMiddleware1(MiddlewareMixin):
    def process_request(self,request):
        print("请求1来了")

    def process_response(self,request,response):
        print('请求1走了')
        return response
    # def process_view(self, request, callback, callback_args, callback_kwargs):
    #     print("中间件1的process_view")
    # def process_exception(self,request,exception):
    #     print(exception)

class MyMiddleware2(MiddlewareMixin):
    def process_request(self,request):
        print("请求2来了")

    def process_response(self,request,response):
        print('请求2走了')
        return response
    # def process_view(self, request, callback, callback_args, callback_kwargs):
    #     print("中间件2的process_view")
    # def process_exception(self,request,exception):
    #     print(exception)

注意:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者
由此总结一下:
中间件的process_request方法是在执行视图函数之前执行的。
当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
不同中间件之间传递的request都是同一个对象
4、process_view
路由匹配成功和视图函数执行之前执行(callback就是视图函数)

def process_view(self, request, callback, callback_args, callback_kwargs):
    pass

5、process_exception
视图函数出错,会执行它(全局异常捕获)(记录日志,哪个ip地址,访问哪个路径,出的错)

###自定义中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render,HttpResponse
class MyMiddleware1(MiddlewareMixin):
    def process_request(self,request):
        print("请求1来了")

    def process_response(self,request,response):
        print('请求1走了')
        return response
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("中间件1的process_view")
    def process_exception(self,request,exception):
        print(exception)

class MyMiddleware2(MiddlewareMixin):
    def process_request(self,request):
        print("请求2来了")

    def process_response(self,request,response):
        print('请求2走了')
        return response
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("中间件2的process_view")
    def process_exception(self,request,exception):
        print(exception)
        return render(request,"404.html")
###视图函数
from django.shortcuts import render,HttpResponse

# Create your views here.

def index(request):
    a
    print("view视图函数")
    return HttpResponse("ok")

###执行结果
请求1来了
请求2来了
中间件1的process_view
中间件2的process_view
name 'a' is not defined
请求2走了
请求1走了
image.png

四、CSRF_TOKEN跨站请求伪造

1、介绍
https://www.cnblogs.com/liuqingzheng/p/9505044.html
2、代码演示csrf攻击

#视图函数
#登陆认证装饰器
def login_auth(func):
    def inner(request,*args,**kwargs):
        if request.session.get("name"):
            return func(request,*args,**kwargs)
        else:
            path = request.get_full_path()
            redirect("/app07/login/?returnUrl=%s"%path)
    return inner
#登陆
def login(request):
    if request.method == "GET":
        return render(request,'login1.html')
    else:
        name = request.POST.get("name")
        pwd = request.POST.get("pwd")
        if name == "xiaohong" and pwd == "123":
            #登陆成功,重定向
            #以及写入session
            request.session["name"] = name
            path = request.GET.get("returnUrl")
            if path:
                return redirect(path)
            else:
                return redirect("/app07/bank/")
        else:
            return HttpResponse("用户名或名密码错误")
#银行
@login_auth
def bank(request):
    return render(request,"bank.html")
#转账
@login_auth
def transfer(request):
    # /transfer/?from=xiaohong&to=xiaoming&total=100
    F = request.GET.get("from")
    T = request.GET.get("to")
    total = request.GET.get("total")
    return HttpResponse("转账成功")
#在不同端口上写一个黑客函数
def hack(request):
    return render(request,"hack.html")

#前端中黑客页面和银行页面地址指向转账
<body>
<a href="/app07/transfer/?from=xiaohong&to=xiaoming&total=100">点我转账</a>
</body>

解释上述例子:用户在登陆成功后,浏览器cookie中会自动生成一个session,用户在没有退出登陆,直接点开其他网站,由于自身携带的session还在,服务端会默认你是可以登入的,从而导致黑客中转账成功
3、django解决了csrf攻击,是用了中间件:django.middleware.csrf.CsrfViewMiddleware
4、后期中间件不能注释,每次发送post请求,都需要携带csrf_token随机字符串
-在form表单中提交

<form action="" method="post">
    {% csrf_token %}
    <p>用户名:<input type="text" name="name"></p>
    <p>密码:<input type="text" name="password"></p>
    <p><input type="submit"></p>
</form>

-在ajax中提交

<body>
{% csrf_token %}  # 可以不写
<p>username:<input type="text" name="username"></p>
<p>pwd:<input type="text" name="pwd"></p>
<input type="submit" value="提交" id="btn">
<script>
    $('#btn').click(function () {
        $.ajax({
            url:'',
            method:'post',
            data:{'username':$('[name="username"]').val(),'pwd':$('[name="pwd"]').val(),
#方式1:放到data中               'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()
            },
#方式二:'csrfmiddlewaretoken':‘{{ csrf_token }}’
#方式三:放到头中:
headers:{'X-CSRFToken':'{{ csrf_token }}'},
            success:function (data) {
                console.log("成功了")
                console.log(data)
            },
            error:function (data) {
                console.log("出现错误")
                console.log(data)
            }
        })
    })
</script>
</body>
#方式四:放在cookie中
获取cookie:$.cookie('csrftoken')
设置cookie:$.cookie('key','value')
删除cookie:$.cookie('key',null)  # 参数null:代表删除此cookie
应用于前后端分离(js操作cookie)
<script>
    $('#btn').click(function () {
#获取cookie中csrftoken的值
        var token = $.cookie("csrftoken")
        $.ajax({
            url:'',
            method:'post',
            data:{'username':$('[name="username"]').val(),'pwd':$('[name="pwd"]').val(),
            },
#可以写在头中
            headers:{'X-CSRFToken':token},
            success:function (data) {
                console.log("成功了")
                console.log(data)
            },
            error:function (data) {
                console.log("出现错误")
                console.log(data)
            }
        })
    })
</script>

首先引入cookie的jquery插件
参考:https://www.cnblogs.com/SongHuiJuan/p/8065289.html

关于csrf的其他操作

1、全站禁用
注释掉中间件 'django.middleware.csrf.CsrfViewMiddleware',
2、全局使用,局部禁用csrf(在视图函数上加装饰器,中间件不能注释,此时这个视图函数已经没有csrf校验了)

from django.views.decorators.csrf import csrf_exempt,csrf_protect
@csrf_exempt
def csrf(request):
    if request.method == "GET":
        return render(request,"csrf.html")
    else:
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        if name == "xiaohong" and pwd == "123":
            return HttpResponse("登陆成功了")
        else:
            return HttpResponse("cuole")

3、全局禁用,局部使用csrf
在视图函数上在装饰器@csrf_protect
4、拓展:古怪的使用的方法,在urls.py中
装饰器直接放在路由内调用

path('csrf_test/', csrf_exempt(views))
视图函数上就不用再写装饰器了
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352