CTFd CSRF 校验模块解读

发布于:2025-05-12 ⋅ 阅读:(12) ⋅ 点赞:(0)

实现上传头像功能的时候遇到了 403,隐约感觉到可能是 csrf 的问题,但是嫌麻烦一直懒得翻源码里的校验逻辑,反而让自己怀疑是 mime type 有限制,走了弯路。

机缘巧合发现了 csrf 的校验位置,总算是通了

定位代码位置

CTFd/__init__.py 文件下,观察如下代码片段

        init_request_processors(app)
        init_template_filters(app)
        init_template_globals(app)

        # Importing here allows tests to use sensible names (e.g. api instead of api_bp)
        from CTFd.admin import admin
        from CTFd.api import api
        from CTFd.auth import auth
        from CTFd.challenges import challenges
        from CTFd.errors import render_error
        from CTFd.events import events
        from CTFd.matches import matches
        from CTFd.scoreboard import scoreboard
        from CTFd.share import social
        from CTFd.teams import teams
        from CTFd.users import users
        from CTFd.views import views
        from CTFd.writeup import writeup
        app.register_blueprint(views)
        app.register_blueprint(teams)
        app.register_blueprint(users)
        app.register_blueprint(matches)
        app.register_blueprint(challenges)

大概能猜出来 csrf 校验应该是在注册蓝图之前初始化的,也就是 init_request_processors。进去后发现一堆 @app.before_request 的装饰器,感觉对了。往下翻,查询 403 找到

@app.before_request
    def csrf():
        try:
            func = app.view_functions[request.endpoint]
        except KeyError:
            abort(404)
        if hasattr(func, "_bypass_csrf"):
            return
        if request.headers.get("Authorization"):
            return
        if not session.get("nonce"):
            session["nonce"] = generate_nonce()
        if request.method not in ("GET", "HEAD", "OPTIONS", "TRACE"):
            if request.content_type == "application/json":
                if session["nonce"] != request.headers.get("CSRF-Token"):
                    abort(403)
            if request.content_type != "application/json":
                if session["nonce"] != request.form.get("nonce"):
                    abort(403)

bingo。原来只有 json 的 csrf token 是放在 header 里的,难怪 403 了。


网站公告

今日签到

点亮在社区的每一天
去签到