Flask 中 AJAX 身份验证的 CSRF 保护

Cha*_*ies 6 python ajax csrf flask

我想对网站上的登录名和注册表单进行 AJAX 化。到目前为止,我一直在使用 WTForms 主要是为了它内置的 CSRF 保护,但是对于这个项目,我觉得它不值得 - 一个额外的抽象层,因此令人沮丧,因为它应该很漂亮简单的。

所以我在 Flask 的安全部分看到了这个片段

@app.before_request
def csrf_protect():
    if request.method == "POST":
        token = session.pop('_csrf_token', None)
        if not token or token != request.form.get('_csrf_token'):
        abort(403)

def generate_csrf_token():
    if '_csrf_token' not in session:
        session['_csrf_token'] = some_random_string()
    return session['_csrf_token']

app.jinja_env.globals['csrf_token'] = generate_csrf_token
Run Code Online (Sandbox Code Playgroud)

我理解这段代码背后的思考过程。事实上,这一切对我来说都很有意义(我认为)。我看不出有什么问题。

但它不起作用。我对代码所做的唯一更改是将伪函数替换为some_random_string()os.urandom(24). 到目前为止,每个请求都有 403'd,因为tokenrequest.form.get('_csrf_token')永远不会相同。当我打印出来这是显而易见的-通常它们是不同的字符串,但偶尔的,貌似没有根本的原因,一方或另一方就会None或输出的删减版本os.urandom(24)。显然有些东西不同步,但我不明白它是什么。

msc*_*arf 5

您可以轻松flask-wtf享受以下便利:

from flask_wtf.csrf import CsrfProtect
Run Code Online (Sandbox Code Playgroud)

然后在 init 上,要么:

CsrfProtect(app)
Run Code Online (Sandbox Code Playgroud)

或者:

csrf = CsrfProtect()

def create_app():
    app = Flask(__name__)
    csrf.init_app(app)
Run Code Online (Sandbox Code Playgroud)

然后令牌将在任何时候在应用程序范围内可用,包括通过jinja2

<form method="post" action="/">
  <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>
Run Code Online (Sandbox Code Playgroud)

(通过文档

  • 请注意:"FlaskWTFDeprecationWarning: "flask_wtf.CsrfProtect" 已重命名为 "CSRFProtect",并将在 1.0 中删除。" (2认同)

Ale*_*voy 3

我认为你的问题是 os.urandom 函数。该函数的结果可能包含无法在 html 中正确解析的符号。因此,当您在 html 中插入 csrf_token 并且不进行任何转义时,就会遇到所描述的问题。

怎么修。 尝试在 html 中转义 csrf_token (请参阅文档)或使用其他方法生成 csrf 令牌。例如使用 uuid:

import uuid
...

def generate_random_string():
    return str(uuid.uuid4())
...
Run Code Online (Sandbox Code Playgroud)