国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

python Flask 裝飾器順序問題解決

2020-01-04 14:54:53
字體:
來源:轉載
供稿:網友

上周 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 裝飾器順序說明

總結一下就是,裝飾的順序按靠近函數順序執行,從內到外裝飾,調用時由外而內,執行順序和裝飾順序相反。

回過頭來看 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_requireddef refresh_session(): pass

這段代碼相當于:

# 這里沒有裝飾器def refresh_session(): passlogin_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(): passroute_wrapped = app.route('/admin/refresh_session/')(refresh_session) # route 裝飾器login_wrapped = login_required(route_wrapped)  # login 裝飾器

/admin/refresh_session/ 這條路由指向的實際是 refresh_session , 而 login_wrapped 并沒有與路由掛勾,所以不會被調用

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到python教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乌海市| 鄂伦春自治旗| 扶余县| 精河县| 沂南县| 嘉黎县| 富宁县| 平南县| 密山市| 四平市| 社会| 乾安县| 屏南县| 岫岩| 司法| 托克逊县| 临安市| 界首市| 始兴县| 辉县市| 唐山市| 安泽县| 同德县| 宁海县| 石首市| 宣武区| 南京市| 札达县| 翼城县| 沂源县| 鄂托克旗| 南雄市| 固原市| 莱阳市| 麻江县| 曲松县| 辽源市| 美姑县| 武胜县| 周口市| 新竹县|