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检查指定文件是否存在的方法
Jul 06 Python
Python Requests 基础入门
Apr 07 Python
Python贪吃蛇游戏编写代码
Oct 26 Python
详谈套接字中SO_REUSEPORT和SO_REUSEADDR的区别
Apr 28 Python
Python调用C++,通过Pybind11制作Python接口
Oct 16 Python
解决Python正则表达式匹配反斜杠''\''问题
Jul 17 Python
Python 中list ,set,dict的大规模查找效率对比详解
Oct 11 Python
Python中的sys.stdout.write实现打印刷新功能
Feb 21 Python
Python填充任意颜色,不同算法时间差异分析说明
May 16 Python
浅析Python 责任链设计模式
Sep 11 Python
Python collections.deque双边队列原理详解
Oct 05 Python
python与idea的集成的实现
Nov 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
flash用php连接数据库的代码
2011/04/21 PHP
php使用Cookie控制访问授权的方法
2015/01/21 PHP
PHP读取XML格式文件的方法总结
2017/02/27 PHP
PHP的mysqli_stat()函数讲解
2019/01/23 PHP
laravel Task Scheduling(任务调度)在windows下的使用详解
2019/10/22 PHP
javascript SocialHistory 检查访问者是否访问过某站点
2008/08/02 Javascript
JavaScript调用堆栈及setTimeout使用方法深入剖析
2013/02/16 Javascript
jquery实现微博文字输入框 输入时显示输入字数 效果实现
2013/07/12 Javascript
js 判断js函数、变量是否存在的简单示例代码
2014/03/04 Javascript
jquery实现导航固定顶部的效果仿蘑菇街
2014/10/22 Javascript
JS获取表格内指定单元格html内容的方法
2015/03/31 Javascript
jQuery验证插件validate使用详解
2016/05/11 Javascript
javascript解析ajax返回的xml和json格式数据实例详解
2017/01/05 Javascript
bootstrap插件treeview实现全选父节点下所有子节点和反选功能
2017/07/21 Javascript
浅谈vue的props,data,computed变化对组件更新的影响
2018/01/16 Javascript
详解node Async/Await 更好的异步编程解决方案
2018/05/10 Javascript
浅析java线程中断的办法
2018/07/29 Javascript
微信小程序和百度的语音识别接口详解
2019/05/06 Javascript
Vue 2.0 中依赖注入 provide/inject组合实战
2019/06/20 Javascript
javascript设计模式 ? 备忘录模式原理与用法实例分析
2020/04/21 Javascript
vue组件讲解(is属性的用法)模板标签替换操作
2020/09/04 Javascript
JavaScript中的Proxy对象
2020/11/27 Javascript
[01:38]DOTA2辉夜杯 欢乐的观众现场采访
2015/12/26 DOTA
Python实现单词翻译功能
2017/06/06 Python
python中嵌套函数的实操步骤
2019/02/27 Python
python从Oracle读取数据生成图表
2020/10/14 Python
如何在pycharm中安装第三方包
2020/10/27 Python
HTML5实现直播间评论滚动效果的代码
2020/05/27 HTML / CSS
Bulk Powders意大利:运动补充在线商店
2019/02/09 全球购物
委托公证书范本
2014/04/03 职场文书
安全责任书范本
2014/04/15 职场文书
社区关爱留守儿童活动方案
2014/08/22 职场文书
班子成员四风问题自我剖析材料
2014/09/29 职场文书
健康状况证明书
2014/11/26 职场文书
2015年测量员工作总结
2015/05/23 职场文书
(开源)微信小程序+mqtt,esp8266温湿度读取
2021/04/02 Javascript