python Flask 装饰器顺序问题解决

作者:Medici.Yan''s Blog 时间:2022-09-30 09:16:42 

上周 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 并没有与路由挂勾,所以不会被调用

来源:http://blog.evalbug.com/2018/08/07/flask_decorator_sequence

标签:Flask,装饰器,顺序
0
投稿

猜你喜欢

  • 使用python-cv2实现视频的分解与合成的示例代码

    2021-06-21 11:51:46
  • 详解python __init__.py 和 __all__作用

    2023-08-22 06:55:22
  • python的函数和方法(上)

    2021-02-04 11:46:16
  • jquery插件bootstrapValidator数据验证详解

    2024-04-10 13:53:14
  • IIS6.0下ASP的新增功能

    2007-08-22 14:55:00
  • Python设计模式行为型责任链模式

    2021-08-15 05:58:16
  • Python之csv文件从MySQL数据库导入导出的方法

    2023-08-09 04:45:10
  • Python selenium get_cookies获取cookie不全的解决方案

    2021-09-17 07:39:52
  • ROS机器人底盘坐标像素变换操作方法

    2023-11-08 20:15:43
  • Python判断变量是否是None写法代码实例

    2021-08-24 12:21:09
  • 使用django的objects.filter()方法匹配多个关键字的方法

    2022-04-08 06:11:20
  • 关于应用UI组件的移动端适配方式

    2024-04-27 16:12:01
  • PHP最常用的正则表达式

    2024-05-03 15:34:38
  • python通过伪装头部数据抵抗反爬虫的实例

    2022-03-11 09:56:04
  • Jinja2实现模板渲染与访问对象属性流程详解

    2022-09-18 14:44:20
  • python Crypto模块的安装与使用方法

    2022-09-17 15:19:01
  • Python图像处理之颜色的定义与使用分析

    2023-03-01 21:07:05
  • Python django框架输入汉字,数字,字符生成二维码实现详解

    2022-12-13 00:23:24
  • Python使用for生成列表实现过程解析

    2021-11-28 08:15:30
  • django中模板继承与ModelForm实例详解

    2021-09-05 18:52:10
  • asp之家 网络编程 m.aspxhome.com