python Flask 装饰器顺序问题解决


Posted in Python onAugust 08, 2018

上周 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 装饰器顺序:

  1. 如果 @app.route 在内层,那么就会把最原始的 view 函数传给 add_url_rule , Flask 框架就会添加一条 URL 规则,指向最原始的 view 函数。
  2. 如果 @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 并没有与路由挂勾,所以不会被调用

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python常用web框架简单性能测试结果分享(包含django、flask、bottle、tornado)
Aug 25 Python
编写简单的Python程序来判断文本的语种
Apr 07 Python
用Python的Tornado框架结合memcached页面改善博客性能
Apr 24 Python
python MNIST手写识别数据调用API的方法
Aug 08 Python
PyCharm设置每行最大长度限制的方法
Jan 16 Python
python 判断三个数字中的最大值实例代码
Jul 24 Python
python生成器用法实例详解
Nov 22 Python
Python-jenkins模块获取jobs的执行状态操作
May 12 Python
Python基于pyjnius库实现访问java类
Jul 31 Python
Python实现byte转integer
Jun 03 Python
linux中nohup和后台运行进程查看及终止
Jun 24 Python
Python字符串常规操作小结
Apr 03 Python
Python BS4库的安装与使用详解
Aug 08 #Python
python特性语法之遍历、公共方法、引用
Aug 08 #Python
用Python shell简化开发
Aug 08 #Python
在Python中使用gRPC的方法示例
Aug 08 #Python
Python实现购物评论文本情感分析操作【基于中文文本挖掘库snownlp】
Aug 07 #Python
python实现彩票系统
Jun 28 #Python
django框架自定义用户表操作示例
Aug 07 #Python
You might like
全国FM电台频率大全 - 7 吉林省
2020/03/11 无线电
在php中取得image按钮传递的name值
2006/10/09 PHP
IIS+PHP+MySQL+Zend配置 (视频教程)
2006/12/13 PHP
基于php上传图片重命名的6种解决方法的详细介绍
2013/04/28 PHP
PHP变量内存分配问题记录整理
2013/11/27 PHP
php使用cookie显示用户上次访问网站日期的方法
2015/01/26 PHP
PHP中捕获超时事件的方法实例
2015/02/12 PHP
通过PHP设置BugFree获取邮箱通知
2019/04/25 PHP
jQuery+CSS 实现随滚动条增减的汽水瓶中的液体效果
2011/09/26 Javascript
js控制CSS样式属性语法对照表
2012/12/11 Javascript
js离开或刷新页面检测(且兼容FF,IE,Chrome)
2014/03/05 Javascript
jquery处理json数据实例分析
2014/06/03 Javascript
三种AngularJS中获取数据源的方式
2016/02/02 Javascript
jquery判断input值不为空的方法
2016/06/05 Javascript
html判断当前页面是否在iframe中的实例
2016/11/30 Javascript
AngularJS双向绑定和依赖反转实例详解
2017/04/15 Javascript
nodejs使用redis作为缓存介质实现的封装缓存类示例
2018/02/07 NodeJs
浅谈Node.js 沙箱环境
2018/05/15 Javascript
详解小程序原生使用ES7 async/await语法
2018/08/06 Javascript
Vue.js点击切换按钮改变内容的实例讲解
2018/08/22 Javascript
详解vue中的computed的this指向问题
2018/12/05 Javascript
react实现同页面三级跳转路由布局
2019/09/26 Javascript
解决vue初始化项目时,一直卡在Project description上的问题
2019/10/31 Javascript
[00:52]玛尔斯技能全介绍
2019/03/06 DOTA
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
简单了解Python matplotlib线的属性
2019/06/29 Python
Golang GBK转UTF-8的例子
2019/08/26 Python
详解Django admin高级用法
2019/11/06 Python
基于python监控程序是否关闭
2020/01/14 Python
使用python从三个角度解决josephus问题的方法
2020/03/27 Python
纯CSS3实现3D旋转书本效果
2016/03/21 HTML / CSS
自荐信写法介绍
2014/01/25 职场文书
档案接收函格式
2015/01/30 职场文书
公司联欢会主持词
2015/07/04 职场文书
银行客户经理培训心得体会
2016/01/09 职场文书
幼儿园教学反思范文
2016/03/02 职场文书