几天前,我已经重置了我的本地烧瓶环境,而没有在删除它之前通过pip freeze
捕获了依赖关系。因此,我不得不重新安装整个堆栈的最新版本。
现在突然之间,我无法再使用表单进行验证。 Flask声称CSRF将丢失。
def register():
form = RegisterForm()
if form.validate_on_submit():
...
return make_response("register.html", form=form, error=form.errors)
我第一次发送Get
我按预期检索空form.errors
。
现在,我填写表单并提交,form.errors
显示:{'csrf_token': [u'CSRF token missing']}
这太奇怪了。我想知道Flask-WTF是否已经改变了,而且我错误地使用了它。
我可以清楚地看到form.CSRF_token
存在,那为什么声称它丢失了?
CSRFTokenField: <input id="csrf_token" name="csrf_token" type="hidden" value="1391278044.35##3f90ec8062a9e91707e70c2edb919f7e8236ddb5">
我从未接触到工作模板,但我在此发布了它:
{% from "_formhelpers.html" import render_field %}
{% extends "base.html" %}
{% block body %}
<div class="center simpleform">
<h2>Register</h2>
{% if error %}<p class=error><strong>Error:</strong> {{ error }}{% endif %}
<form class="form-signin" action="{{ url_for('register') }}" method=post>
{{form.hidden_tag()}}
<dl>
{{ render_field(form.name) }}
{{ render_field(form.email) }}
{{ render_field(form.password) }}
{{ render_field(form.confirm) }}
<dd><input type=submit value=Register class='btn btn-primary'>
</dl>
</form>
</div>
{% endblock %}
这是一个新错误吗?
更新
我重新安装了所有内容,问题仍然存在。
正如Martijn建议的那样,我正在调试flask_wtf
中的以下方法:
def validate_csrf_token(self, field):
if not self.csrf_enabled:
return True
if hasattr(request, 'csrf_valid') and request.csrf_valid:
# this is validated by CsrfProtect
return True
if not validate_csrf(field.data, self.SECRET_KEY, self.TIME_LIMIT):
raise ValidationError(field.gettext('CSRF token missing'))
最后一个条件是提高验证错误。
field.data = "1391296243.8##1b02e325eb0cd0c15436d0384f981f06c06147ec"
self.SECRET_KEY = None (? Is this the problem)
self.TIME_LIMIT = 3600
你说得对,HMAC比较失败......两个值都在不同的时间。
return hmac_compare == hmac_csrf
我的配置中定义了SECRET_KEY和CSRF_SESSION_KEY。
答案 0 :(得分:19)
Flask-WTF CSRF基础设施在以下情况下拒绝令牌:
令牌丢失。不是这里的情况,您可以在表单中看到令牌。
太旧了(默认过期时间设置为3600秒或一小时)。在表单上设置TIME_LIMIT
属性以覆盖此属性。可能不是这里的情况。
如果在当前会话中找不到'csrf_token'
密钥。您显然可以看到会话令牌,因此也是如此。
如果HMAC签名不匹配;签名基于'csrf_token'
密钥下的会话中设置的随机值,服务器端密钥以及令牌中的到期时间戳。
消除了前三种可能性后,您需要验证第四步失败的原因。您可以在flask_wtf/csrf.py
函数的validate_csrf()
文件中调试验证。
对于您的设置,您需要验证会话设置是否正确(特别是如果您不使用默认会话配置),并且您使用的是正确的服务器端密码。表单本身可能设置了SECRET_KEY
属性,但在请求之间不稳定,或者应用WTF_CSRF_SECRET_KEY
键已更改(后者默认为app.secret_key
value)。
版本0.9.0中添加了CSRF支持,如果升级,请查看特定的CSRF protection documentation。标准的Flask-WTF Form
类将 CSRF令牌包含为隐藏字段,使隐藏字段足以包含它:
{{ form.hidden_tag() }}
答案 1 :(得分:16)
经过近一天的努力,我终于找到了问题。 :( 非常感谢Martijn的帮助。
实际问题在于最新flask_wtf.csrf
的工作方式。制造商已经完全彻底改革了它。
您必须用模板替换模板中的所有{{form.hidden_tag()}}
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
。
现在,您必须通过添加CsrfProtect(app)
来明确启用CSRF保护。
documentation现在显然反映了这一点,但我不知道这已经发生变化并且在追逐鬼魂。
在不以某种方式通知开发人员的情况下,已弃用的功能是一个大问题。任何现在升级到最新版本的人都会像我一样追逐鬼魂。但它也是我的错,没有拍摄我的依赖关系的快照。课程学到了很多东西。
答案 2 :(得分:0)
对我来说,问题不是出自Flask-WTF配置错误或缺少令牌。 来自环境变量。
如果您的Flask服务器未在本地主机上运行,则为了使Flask正常运行,您需要设置一个SERVER_NAME
环境变量。您可能忘记了在某个地方修改SERVER_NAME
值。
例如,您可以在config/settings.py
中输入以下内容:
SERVER_NAME = 'my-domain.com'
有关更多信息,请查看this great resource
答案 3 :(得分:0)
在创建应用程序时:
from flask_wtf.csrf import CsrfProtect
csrf = CsrfProtect()
app = Flask(__name__)
...
csrf.init_app(app)
...