繁体   English   中英

Flask JWT 扩展缺少 csrf 访问令牌

[英]Flask JWT Extended missing csrf access token

我的 flask 应用程序使用 JWT 作为身份验证手段。 这些令牌存储在 cookies 中,flask-jwt-extended 配置为使用它们。 对于常规的 GET 请求,身份验证工作正常, @jwt_required装饰器能够从 cookies 读取令牌并对用户进行身份验证。 但是,当使用fetch()发出 AJAX POST 请求时,扩展程序无法读取它们并返回Missing CSRF token错误。 奇怪的是,当在 POST 路由中访问请求 object 时,所有必需的 cookies 以及所有其他路由中都存在,这意味着fetch()正确设置了所有必需的 cookies:

ImmutableMultiDict([
('csrftoken', 'valid_csrf_token'),
('session','valid_session_cookie'), 
('access_token_cookie', 'valid_access_token'), 
('csrf_access_token', 'valid_csrf_access_token')
])

Flask POST 路线:

@main.route("/sendmail", methods=["POST"])
@jwt_required()
async def send_mail():
    data = json.loads(request.data)
    
    mail_template = render_template("mail-view.html", data=data)

    pdf_report = pdfkit.from_string(mail_template, False)

    message = Message(
        subject="Flask-Mailing module",
        recipients=["recepient-mail@domain.com"],
        body="Message body",
        subtype="html",
    )
    message.attach("report.pdf", pdf_report)
    await mail.send_message(message)
    return jsonify({"message": "success"}), 200

获取请求:

fetch(window.location.origin + "/sendmail", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    credentials: "same-origin",
    body: JSON.stringify(mail),
})

我的应用程序配置 object:

class DevConfig:
    SECRET_KEY = os.environ.get("SECRET_KEY")
    JWT_SECRET_KEY = os.environ.get("JWT_SECRET_KEY")
    JWT_COOKIE_SECURE = False
    SESSION_COOKIE_SECURE = False
    JWT_TOKEN_LOCATION = ["cookies"]
    JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(hours=1)

    MAIL_SERVER = "smtp.googlemail.com"
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USE_SSL = False
    MAIL_USERNAME = os.environ.get("MAIL_USERNAME")
    MAIL_PASSWORD = os.environ.get("MAIL_PASSWORD")
    MAIL_FROM = os.environ.get("MAIL_USERNAME")

使用 flask-jwt-extended 默认设置,CSRF-Token 只需要为 state 更改请求方法(除“GET”之外的所有内容)发送。 这就是为什么即使没有 CSRF 令牌也可以授权“GET”方法的原因。 其次,CSRF-Token 的整个想法是不通过 web 浏览器自动发送它,因此它不被 cookie 接受:

默认情况下,我们通过在有人登录时设置两个 cookies 来完成此操作。第一个 cookie 包含 JWT,并编码为 JWT 是双重提交令牌。 此 cookie 设置为仅限 http,因此无法通过 javascript 访问(这是防止 XSS 攻击能够窃取 JWT 的原因)。 我们设置的第二个 cookie 仅包含相同的双重提交令牌,但这次是在 javascript 可读的 cookie 中。 每当发出请求时,都需要包含一个 X-CSRF-TOKEN header,以及双重提交令牌的值。 如果此 header 中的值与存储在 JWT 中的值不匹配,则请求被踢出无效。

https://flask-jwt-extended.readthedocs.io/en/stable/token_locations/

因此,每当您发送请求时,都应将 CSRF-Token 添加到标头中:

fetch(window.location.origin + "/sendmail", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-CSRF-TOKEN": getCookie("csrf_access_token"),
    },
    credentials: "same-origin",
    body: JSON.stringify(mail),
})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM