python Flask 装饰器顺序问题解决
作者:Medici.Yan''s Blog 发布时间:2022-09-30 09:16:42
上周 RealWorld CTF 2018 web 题 bookhub 有个未授权访问的漏洞,比较有意思,赛后看了一下公开的 WriteUp,大家也都没写清楚,所以就有了这篇博文。
前言
这个题是用 flask 框架写的,在 www/bookhub/views/user.py
中, refresh_session
方法存在未授权访问漏洞,代码是这样写的:
@login_required
@user_blueprint.route('/admin/system/refresh_session/', methods=['POST'])
def refresh_session():
pass # 这里省略内容
注意看 @login_required
这个装饰器写在了 route
装饰器上面了,导致了 login_required
未调用。那么,为什么会这样子呢?
官方文档
Flask 官方文档中关于Login Required Decorator说明 这一节里面有一行说明:
To use the decorator, apply it as innermost decorator to a view function. When applying further decorators, always remember that the route() decorator is the outermost.
大概意思就是,必须保证 route 装饰器在最顶层
那么为什么要这样提示呢?
Python 装饰器顺序说明
本节内容可直接参考: Python 装饰器执行顺序迷思
总结一下就是,装饰的顺序按靠近函数顺序执行,从内到外装饰,调用时由外而内,执行顺序和装饰顺序相反。
回过头来看 Flask
Flask 框架中, route
装饰器是这么写的:
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
route
调用了 add_url_rule
, 对传入的 f
添加一条 URL 规则。
所以,按照 python 装饰器顺序:
如果
@app.route
在内层,那么就会把最原始的 view 函数传给 add_url_rule , Flask 框架就会添加一条 URL 规则,指向最原始的 view 函数。如果
@app.route
在外层,那么就会把已经被 login_required 装饰过的 view 函数传给 add_url_rule , Flask 框架就会添加一条 URL 规则,指向已经装饰过的 view 函数。
下面是两个例子,来说明:
正确写法
@user_blueprint.route('/admin/refresh_session/', methods=['POST'])
@login_required
def refresh_session():
pass
这段代码相当于:
# 这里没有装饰器
def refresh_session():
pass
login_wrapped = login_required(refresh_session) # login 装饰器
both_wrapped = app.route('/admin/refresh_session/')(login_wrapped) # route 装饰器
/admin/refresh_session/
这条路由指向的实际是 login_wrapped
,这样就会经过 login 检查
错误写法
@login_required
@user_blueprint.route('/admin/refresh_session/', methods=['POST'])
def refresh_session():
pass
这段代码相当于:
# 这里没有装饰器
def refresh_session():
pass
route_wrapped = app.route('/admin/refresh_session/')(refresh_session) # route 装饰器
login_wrapped = login_required(route_wrapped) # login 装饰器
/admin/refresh_session/
这条路由指向的实际是 refresh_session
, 而 login_wrapped
并没有与路由挂勾,所以不会被调用
来源:http://blog.evalbug.com/2018/08/07/flask_decorator_sequence
猜你喜欢
- 组件:"Adodb.Stream" 有下列方法: Canc
- Flask-Login 为 Flask 提供用户会话管理。它处理登录、注销和长时间记住用户会话等常见任务。Flask-Login 不绑定到任
- kelon 问:格式如下:s="地,在要,大,奇功,不知,但是,不示"我想把它split分出來,变成数组來循环,但是不知
- 前言:python数据类型: python数据结构之数据类型.今天我们主要来介绍一些内置函数,比如输入输出,控制,和异常的用法,尤其是输出和
- 目录连接池是什么?为什么需要连接池?连接池的原理是什么?使用python语言自制简易mysql连接池开始使用自定义配置文件名 & 配
- 本文研究的主要是Django中Forms的使用,具体如下。创建文件do.html{% extends 'base.html'
- 前言前文讲述了ppi-cpi和m0-m1-m2的图形绘制,在本文中继续分享一个反映经济活动景气度的指标PMI,在本文中还是采用爬虫的方式获取
- 1. 安装vim:# apt-get install -y vim-gnome2. 安装ctags,ctags用于支持tagli
- 前言对于专业的python程序员来说,python打包工具或许用得并不多。但是对于非专业人士来说,你给他写个python项目,要让他安装py
- 相信很多学编程的人都对Vlookup函数不陌生,一些在excel中不方便处理的大量数据,用Python就可以轻松解决。下面介绍openpyx
- 不知道有多少人是被这个头图骗进来的:)事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八
- 本文实例讲述了python使用append合并两个数组的方法。分享给大家供大家参考。具体如下:lista = [1,2,3]listb =
- 可实现功能:1.随机生成一个整数。2.随机生成任意范围内的一个整数。3.随机生成指定长度的整数组4.随机生成指定长度的任意范围的整数组5.随
- 先来看看什么是书签查找: 当优化器所选择的非聚簇索引只包含查询请求的一部分字段时,就需要一个查找(lookup)来检索其他字段来满足请求。对
- 最近,Analysis with Programming加入了Planet Python。作为该网站的首批特约博客,我这里来分享一下如何通过
- 1.执行cmd命令,不显示执行过程中弹出的黑框def run_cmd( cmd_str='', echo_print=1):
- 原文:10 Principles Of Effective Web Design翻译:熊猫2008-02-03本文由熊猫同学授权翻译首发。并
- 算法是计算机科学中一个重要的研究方向,是解决复杂问题的关键。在计算机世界中,算法无处不在。数据库是存储数据和执行大批量计算的场所,在数据库中
- 导读我们在使用selenium打开google浏览器的时候,默认打开的是一个新的浏览器窗口,而且里面不带有任何的浏览器缓存信息。当我们想要爬
- global语句的作用在编写程序的时候,如果想为一个在函数外的变量重新赋值,并且这个变量会作用于许多函数中时,就需要告诉python这个变量