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计算程序开始到程序结束的运行时间和程序运行的CPU时间
Nov 28 Python
Python绑定方法与非绑定方法详解
Aug 18 Python
解决python有时候import不了当前的包问题
Aug 28 Python
Python字典的概念及常见应用实例详解
Oct 30 Python
Python字符串的修改方法实例
Dec 19 Python
学会python自动收发邮件 代替你问候女友
May 20 Python
Python控制台实现交互式环境执行
Jun 09 Python
pycharm如何设置官方中文(如何汉化)
Dec 29 Python
Django+Django-Celery+Celery的整合实战
Jan 20 Python
pytorch 梯度NAN异常值的解决方案
Jun 05 Python
使用Django框架创建项目
Jun 10 Python
python语言中pandas字符串分割str.split()函数
Aug 05 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
用PHP实现小型站点广告管理
2006/10/09 PHP
php实现在服务器端调整图片大小的方法
2015/06/16 PHP
php连接sftp的作用以及实例代码
2019/09/23 PHP
Jquery cookie操作代码
2010/03/14 Javascript
基于jquery的表格排序
2010/09/11 Javascript
兼容IE和FF的js脚本代码小结(比较常用)
2010/12/06 Javascript
基于jQuery实现的百度导航li拖放排列效果,即时更新数据库
2012/07/31 Javascript
jQuery动画效果-slideUp slideDown上下滑动示例代码
2013/08/28 Javascript
ajax请求乱码的解决方法(中文乱码)
2014/04/10 Javascript
Javascript中设置默认参数值示例
2014/09/11 Javascript
JavaScript类继承及实例化的方法
2015/07/25 Javascript
javascript 使用正则test( )第一次是 true,第二次是false
2017/02/22 Javascript
jQuery插件FusionWidgets实现的Cylinder图效果示例【附demo源码】
2017/03/23 jQuery
jQuery实现点击自身以外区域关闭弹出层功能完整示例【改进版】
2018/07/31 jQuery
vue双向绑定及观察者模式详解
2019/03/19 Javascript
JavaScript实现简单进度条效果
2020/03/25 Javascript
微信小程序开发数据缓存基础知识辨析及运用实例详解
2020/11/06 Javascript
vue打开新窗口并实现传参的图文实例
2021/03/04 Vue.js
[41:37]DOTA2北京网鱼队选拔赛——冲击职业之路
2015/04/13 DOTA
[03:12]完美世界DOTA2联赛PWL DAY7集锦
2020/11/06 DOTA
python获取list下标及其值的简单方法
2016/09/12 Python
简单实现python进度条脚本
2017/12/18 Python
异步任务队列Celery在Django中的使用方法
2018/06/07 Python
Python中py文件转换成exe可执行文件的方法
2019/06/14 Python
使用虚拟环境打包python为exe 文件的方法
2019/08/29 Python
TensorFlow2.1.0安装过程中setuptools、wrapt等相关错误指南
2020/04/08 Python
Python新手学习标准库模块命名
2020/05/29 Python
python 元组和列表的区别
2020/12/30 Python
轻松掌握CSS3中的字体大小单位rem的使用方法
2016/05/24 HTML / CSS
什么是URL
2015/12/13 面试题
在浏览器端如何得到服务器端响应的XML数据
2012/11/24 面试题
蔬菜基地的创业计划书
2014/01/06 职场文书
企业内部培训方案
2014/02/04 职场文书
党员个人批评与自我批评
2014/10/14 职场文书
一年之计:2019年下半年的计划
2019/05/07 职场文书
Mysql 一主多从的部署
2022/05/20 MySQL