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在windows下实现备份程序实例
Jul 04 Python
Python使用Flask框架获取当前查询参数的方法
Mar 21 Python
Python实现的数据结构与算法之队列详解
Apr 22 Python
Python中字典的浅拷贝与深拷贝用法实例分析
Jan 02 Python
Python使用matplotlib绘制三维图形示例
Aug 25 Python
浅谈python脚本设置运行参数的方法
Dec 03 Python
python3使用print打印带颜色的字符串代码实例
Aug 22 Python
Python中turtle库的使用实例
Sep 09 Python
python中文分词库jieba使用方法详解
Feb 11 Python
Python urlencode和unquote函数使用实例解析
Mar 31 Python
python生成xml时规定dtd实例方法
Sep 21 Python
解决python3安装pandas出错的问题
May 20 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
PHP Ajax实现页面无刷新发表评论
2007/01/02 PHP
用C/C++扩展你的PHP 为你的php增加功能
2012/09/06 PHP
php使用cookie实现记住登录状态
2015/04/27 PHP
php文件压缩之PHPZip类用法实例
2015/06/18 PHP
使用PHP实现下载CSS文件中的图片
2015/12/06 PHP
Jqyery中同等与js中windows.onload的应用
2011/05/10 Javascript
Kibo 用于处理键盘事件的Javascript工具库
2011/10/28 Javascript
js常用代码段整理
2011/11/30 Javascript
Javascript this 的一些学习总结
2012/08/31 Javascript
理解JAVASCRIPT中hasOwnProperty()的作用
2013/06/05 Javascript
JavaScript运行时库属性一览表
2014/03/14 Javascript
判断字符串的长度(优化版)中文占两个字符
2014/10/30 Javascript
Jquery 实现checkbox全选方法
2015/01/28 Javascript
JS+CSS实现表格高亮的方法
2015/08/05 Javascript
基于jQuery实现在线选座之高铁版
2015/08/24 Javascript
js实现仿百度风云榜可重复多次调用的TAB切换选项卡效果
2015/08/31 Javascript
使用bootstrap validator的remote验证代码经验分享(推荐)
2016/09/21 Javascript
浅谈jQuery中Ajax事件beforesend及各参数含义
2016/12/03 Javascript
Bootstrap实现圆角、圆形头像和响应式图片
2016/12/14 Javascript
Angular directive递归实现目录树结构代码实例
2017/05/05 Javascript
JavaScript之filter_动力节点Java学院整理
2017/06/28 Javascript
nodejs微信开发之接入指南
2019/03/17 NodeJs
vue双向绑定及观察者模式详解
2019/03/19 Javascript
vue实现点击按钮下载文件功能
2019/10/11 Javascript
在Layui中操作数据表格,给指定单元格添加事件示例
2019/10/26 Javascript
[01:12:44]VG vs Mineski Supermajor 败者组 BO3 第二场 6.6
2018/06/07 DOTA
[50:38]DOTA2-DPC中国联赛 正赛 Phoenix vs CDEC BO3 第二场 3月7日
2021/03/11 DOTA
python 3.6 tkinter+urllib+json实现火车车次信息查询功能
2017/12/20 Python
python如何实现异步调用函数执行
2019/07/08 Python
python 自定义异常和主动抛出异常(raise)的操作
2020/12/11 Python
美国波西米亚风格精品店:South Moon Under
2019/10/26 全球购物
社区包粽子活动方案
2014/01/21 职场文书
工商管理专业自荐信
2014/06/03 职场文书
质量主管工作职责
2014/09/26 职场文书
圣诞晚会主持词
2015/07/01 职场文书
学校教代会开幕词
2016/03/04 职场文书