Flask 中 AJAX 身份验证的 CSRF 保护
Posted
技术标签:
【中文标题】Flask 中 AJAX 身份验证的 CSRF 保护【英文标题】:CSRF protection on AJAX authentication in Flask 【发布时间】:2014-12-19 13:50:34 【问题描述】:我想对网站上的登录和注册表单进行 AJAXify。到目前为止,我一直在使用 WTForms 主要是为了它内置的 CSRF 保护,但对于这个项目,我觉得它不值得——额外的抽象层,因此很沮丧,因为它应该很漂亮很简单。
所以我在 Flask 的安全部分遇到了this snippet:
@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
我了解这段代码背后的思考过程。事实上,这一切对我来说都很有意义(我认为)。我看不出有什么问题。
但它不起作用。我对代码所做的唯一更改是将伪函数some_random_string()
替换为对os.urandom(24)
的调用。到目前为止,每个请求都有 403,因为 token
和 request.form.get('_csrf_token')
永远不会相同。当我打印它们时,这变得很明显——通常它们是不同的字符串,但偶尔,并且似乎没有根本原因,一个或另一个将是None
或os.urandom(24)
输出的截断版本。显然有些东西不同步,但我不明白它是什么。
【问题讨论】:
【参考方案1】:我认为你的问题是 os.urandom 函数。此函数的结果可能包含无法在 html 中正确解析的符号。因此,当您在 html 中插入 csrf_token 并且不进行任何转义时,您就会遇到所描述的问题。
如何解决。 尝试在 html (see docs) 中转义 csrf_token 或使用其他方法生成 csrf 令牌。例如使用 uuid:
import uuid
...
def generate_random_string():
return str(uuid.uuid4())
...
【讨论】:
我想我应该提到我对 urandom() 的输出进行了 base64 编码。显然这不是正确的解决方案。有机会我会尽快检查您的解决方案。 我为你的努力投了赞成票,但不幸的是问题仍然存在。在模板中对generate_csrf_token()
的调用工作正常(reqest.form.get('_csrf_token')
正在正确访问令牌),但由于某种原因它不在会话中。它打印为None
,我完全不明白,因为app.jinja_env.globals['csrf_token']
使用它。在调用generate_csrf_token()
和csrf_protect()
之间的某个地方,它会从会话中消失并根据session.pop('_csrf_token', None)
返回None
。但它只是被使用了!
可以给会话配置吗?
我居然最终解决了这个问题,答案很尴尬。当我第一次开始这个项目时,我安装了 WTForms 和 flask-wtf(很大程度上是出于习惯),然后才决定放弃它们。在删除了我的大部分代码后,我意识到是他们内置的 CSRF 保护干扰了我正在尝试做的事情。不过,我非常感谢您花时间帮助我。【参考方案2】:
您可以获得flask-wtf
的便利,而无需繁重,也无需自己动手:
from flask_wtf.csrf import CsrfProtect
然后在初始化时:
CsrfProtect(app)
或:
csrf = CsrfProtect()
def create_app():
app = Flask(__name__)
csrf.init_app(app)
令牌将在任何时候在应用范围内可用,包括通过jinja2
:
<form method="post" action="/">
<input type="hidden" name="csrf_token" value=" csrf_token() " />
</form>
(通过docs)
【讨论】:
请注意:“FlaskWTFDeprecationWarning: "flask_wtf.CsrfProtect" 已重命名为 "CSRFProtect" 并将在 1.0 中删除。"以上是关于Flask 中 AJAX 身份验证的 CSRF 保护的主要内容,如果未能解决你的问题,请参考以下文章
用于ajax调用的spring security csrf保护
如何通过 AJAX 使用 Flask-WTForms CSRF 保护?