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获取服务器信息的最简单实现方法
Mar 05 Python
Python的Django框架中的URL配置与松耦合
Jul 15 Python
Python之Scrapy爬虫框架安装及使用详解
Nov 16 Python
Django 使用Ajax进行前后台交互的示例讲解
May 28 Python
浅谈Python脚本开头及导包注释自动添加方法
Oct 27 Python
Python CVXOPT模块安装及使用解析
Aug 01 Python
python tornado修改log输出方式
Nov 18 Python
解决tensorflow由于未初始化变量而导致的错误问题
Jan 06 Python
手把手教你从PyCharm安装到激活(最新激活码),亲测有效可激活至2089年
Nov 25 Python
如何基于matlab相机标定导出xml文件
Nov 02 Python
浅析pandas随机排列与随机抽样
Jan 22 Python
如何用python插入独创性声明
Mar 31 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
如何限制访问者的ip(PHPBB的代码)
2006/10/09 PHP
PHP5.2中date()函数显示时间与北京时间相差8小时的解决办法
2009/05/28 PHP
PHP排序算法的复习和总结
2012/02/15 PHP
PHP连接和操作MySQL数据库基础教程
2014/09/29 PHP
CI框架中site_url()和base_url()的区别
2015/01/07 PHP
PHP中Laravel 关联查询返回错误id的解决方法
2017/04/01 PHP
小巧强大的jquery layer弹窗弹层插件
2015/12/06 Javascript
jQuery实现鼠标经过购物车出现下拉框代码(推荐)
2016/07/21 Javascript
基于bootstrap实现广告轮播带图片和文字效果
2016/07/22 Javascript
用jQuery的AJax实现异步访问、异步加载
2016/11/02 Javascript
javascript高级模块化require.js的具体使用方法
2017/10/31 Javascript
vue 中directive功能的简单实现
2018/01/05 Javascript
JS从非数组对象转数组的方法小结
2018/03/26 Javascript
动态加载JavaScript文件的3种方式
2018/05/05 Javascript
Vue 中axios配置实例详解
2018/07/27 Javascript
vue踩坑记-在项目中安装依赖模块npm install报错
2019/04/02 Javascript
vue页面更新patch的实现示例
2020/03/25 Javascript
[01:21]DOTA2 新英雄 森海飞霞
2020/12/18 DOTA
Python多进程机制实例详解
2015/07/02 Python
python调用fortran模块
2016/04/08 Python
Django返回json数据用法示例
2016/09/18 Python
python和c语言的主要区别总结
2019/07/07 Python
python读取大文件越来越慢的原因与解决
2019/08/08 Python
使用Nibabel库对nii格式图像的读写操作
2020/07/01 Python
Python字典fromkeys()方法使用代码实例
2020/07/20 Python
python 实现socket服务端并发的四种方式
2020/12/14 Python
用CSS3实现无限循环的无缝滚动的示例代码
2017/11/01 HTML / CSS
简洁自适应404页面HTML好看的404源码
2020/12/16 HTML / CSS
日本一家专门经营各种箱包的大型网站:Traveler Store
2016/08/03 全球购物
伦敦剧院门票:From The Box Office
2018/06/30 全球购物
世界上最好的足球商店:Unisport
2019/03/02 全球购物
HOTEL INFO英国:搜索全球酒店
2019/08/08 全球购物
斯洛伐克最大的婴儿食品和用品网上商店:Feedo.sk
2020/12/21 全球购物
应届生法律顾问求职信
2013/11/19 职场文书
预备党员转正考核材料
2014/06/03 职场文书
给下属加薪申请报告
2015/05/15 职场文书