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解决汉字编码问题:Unicode Decode Error
Jan 19 Python
Python内建函数之raw_input()与input()代码解析
Oct 26 Python
使用Python搭建虚拟环境的配置方法
Feb 28 Python
python获取代码运行时间的实例代码
Jun 11 Python
Python 打印中文字符的三种方法
Aug 14 Python
Python面向对象之静态属性、类方法与静态方法分析
Aug 24 Python
Python中修改字符串的四种方法
Nov 02 Python
python模块之subprocess模块级方法的使用
Mar 26 Python
使用pandas实现连续数据的离散化处理方式(分箱操作)
Nov 22 Python
Flask中endpoint的理解(小结)
Dec 11 Python
Python Django中的STATIC_URL 设置和使用方式
Mar 27 Python
python -v 报错问题的解决方法
Sep 15 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
如何选购合适的收音机
2021/03/01 无线电
CodeIgniter php mvc框架 中国网站
2008/05/26 PHP
浅谈ThinkPHP的URL重写
2014/11/25 PHP
ThinkPHP函数详解之M方法和R方法
2015/09/10 PHP
php阳历转农历优化版
2016/08/08 PHP
PHP打印输出函数汇总
2016/08/28 PHP
PHP自定义错误用法示例
2016/09/28 PHP
利用Laravel事件系统如何实现登录日志的记录详解
2017/05/20 PHP
TP(thinkPHP)框架多层控制器和多级控制器的使用示例
2018/06/13 PHP
jQuery实现简单的间隔向上滚动效果
2015/03/09 Javascript
JavaScript中split() 使用方法汇总
2015/04/17 Javascript
JS实现按比例缩放图片的方法(附C#版代码)
2015/12/08 Javascript
Nodejs爬虫进阶教程之异步并发控制
2016/02/15 NodeJs
jquery 动态合并单元格的实现方法
2016/08/26 Javascript
深入理解Angular4订阅(Subscribe)与取消
2017/11/22 Javascript
javaScript实现游戏倒计时功能
2018/11/17 Javascript
详解基于webpack&gettext的前端多语言方案
2019/01/29 Javascript
[01:14:31]Secret vs VG 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
布同 统计英文单词的个数的python代码
2011/03/13 Python
Python的Flask框架应用调用Redis队列数据的方法
2016/06/06 Python
Python 递归函数详解及实例
2016/12/27 Python
Python通过命令开启http.server服务器的方法
2017/11/04 Python
python矩阵转换为一维数组的实例
2018/06/05 Python
django实现模型字段动态choice的操作
2020/04/01 Python
解决flask接口返回的内容中文乱码的问题
2020/04/03 Python
python 字典item与iteritems的区别详解
2020/04/25 Python
python脚本使用阿里云slb对恶意攻击进行封堵的实现
2021/02/04 Python
使用CSS3代码绘制可爱的Hello Kitty猫
2016/08/03 HTML / CSS
纯css3实现鼠标经过图片显示描述的动画效果
2014/09/01 HTML / CSS
乐高积木玩具美国官网:LEGO Shop US
2016/09/16 全球购物
Quiksilver美国官网:始于1969年的优质冲浪服和滑雪板外套
2020/04/20 全球购物
我心目中的好老师活动方案
2014/08/19 职场文书
公司法人授权委托书范本
2014/09/12 职场文书
领导干部遵守党的政治纪律情况思想汇报
2014/09/14 职场文书
专题组织生活会发言材料
2014/10/17 职场文书
工程项目经理岗位职责
2015/02/02 职场文书