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中操作时间之mktime()方法的使用教程
May 22 Python
Python中的默认参数实例分析
Jan 29 Python
教你使用python画一朵花送女朋友
Mar 29 Python
Python 实现使用dict 创建二维数据、DataFrame
Apr 13 Python
详解Python中的四种队列
May 21 Python
浅谈Python中的bs4基础
Oct 21 Python
Python类的继承、多态及获取对象信息操作详解
Feb 28 Python
pyqt 实现为长内容添加滑轮 scrollArea
Jun 19 Python
基于python实现从尾到头打印链表
Nov 02 Python
Python错误的处理方法
Jun 23 Python
PySwarms(Python粒子群优化工具包)的使用:GlobalBestPSO例子解析
Apr 05 Python
Python实现简单的俄罗斯方块游戏
Sep 25 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
php5.3 废弃函数小结
2010/05/16 PHP
分享PHP计算两个日期相差天数的代码
2015/12/23 PHP
jquery 合并内容相同的单元格(示例代码)
2013/12/13 Javascript
javascript中Date format(js日期格式化)方法小结
2015/12/17 Javascript
node.js中 stream使用教程
2016/08/28 Javascript
jQuery自定义图片上传插件实例代码
2017/04/04 jQuery
基于JavaScript实现的插入排序算法分析
2017/04/14 Javascript
JavaScript 获取元素在父节点中的下标(推荐)
2017/06/28 Javascript
js移动端事件基础及常用事件库详解
2017/08/15 Javascript
node.js中axios使用心得总结
2017/11/29 Javascript
在vue.js中使用JSZip实现在前端解压文件的方法
2018/09/05 Javascript
详解Vue内部怎样处理props选项的多种写法
2018/11/06 Javascript
JavaScript使用Math.random()生成简单的验证码
2019/01/21 Javascript
Vue 2.0 侦听器 watch属性代码详解
2019/06/19 Javascript
vue分页器组件编写方法详解
2019/06/28 Javascript
vue多页面项目中路由使用history模式的方法
2019/09/23 Javascript
mpvue实现左侧导航与右侧内容的联动
2019/10/21 Javascript
vue router返回到指定的路由的场景分析
2020/11/10 Javascript
[02:32]DOTA2亚洲邀请赛 C9战队出场宣传片
2015/02/07 DOTA
[47:26]完美世界DOTA2联赛 LBZS vs Forest 第二场 11.07
2020/11/09 DOTA
python数据结构之二叉树的建立实例
2014/04/29 Python
Django 生成登陆验证码代码分享
2017/12/12 Python
python微信跳一跳系列之棋子定位颜色识别
2018/02/26 Python
python DataFrame 修改列的顺序实例
2018/04/10 Python
python判断完全平方数的方法
2018/11/13 Python
Python3实现腾讯云OCR识别
2018/11/27 Python
Python3.5迭代器与生成器用法实例分析
2019/04/30 Python
python conda操作方法
2019/09/11 Python
Bjorn Borg官方网上商店:国际运动时尚品牌
2016/08/27 全球购物
美国著名首饰网站:BaubleBar
2016/08/29 全球购物
Java和Javasciprt的区别
2012/09/02 面试题
房地产活动策划方案
2014/05/14 职场文书
离职证明格式样本
2015/06/12 职场文书
立案决定书范文
2015/06/24 职场文书
外出学习心得体会范文
2016/01/18 职场文书
导游词之峨眉山
2019/12/16 职场文书