由于缺少 CSRF,表单验证失败 [英] Form validation fails due missing CSRF

查看:36
本文介绍了由于缺少 CSRF,表单验证失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几天前,我重置了我的本地烧瓶环境,但在删除之前没有通过 pip freeze 捕获依赖项.因此我不得不重新安装整个堆栈的最新版本.

现在突然间我无法再使用表单进行验证了.Flask 声称 CSRF 将丢失.

def register():表单 = 注册表单()如果 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 %}{% 扩展 "base.html" %}{% 块体 %}<div class="center simpleform"><h2>注册</h2>{% if error %}<p class=error><strong>错误:</strong>{{ 错误 }}{% 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></表单>

{% 结束块 %}

这是一个新错误吗?

更新:

我已经重新安装了所有东西,但问题仍然存在.

正如 Martijn 所建议的,我正在调试 flask_wtf 中的以下方法:

def validate_csrf_token(self, field):如果不是 self.csrf_enabled:返回真如果 hasattr(request, 'csrf_valid') 和 request.csrf_valid:# 这是由 CsrfProtect 验证的返回真如果不是 validate_csrf(field.data, self.SECRET_KEY, self.TIME_LIMIT):引发 ValidationError(field.gettext('CSRF token missing'))

最后一个条件是引发验证错误.

field.data = "1391296243.8##1b02e325eb0cd0c15436d0384f981f06c06147ec"self.SECRET_KEY = None(?这是问题所在)self.TIME_LIMIT = 3600

你是对的 HMAC 比较失败......两个值每次都不同.

返回 hmac_compare == hmac_csrf

我的配置中同时定义了 SECRET_KEY 和 CSRF_SESSION_KEY.

解决方案

Flask-WTF CSRF 基础设施在以下情况下拒绝令牌:

  • 令牌丢失.不是这里的情况,您可以在表单中看到令牌.

  • 它太旧了(默认过期时间设置为 3600 秒,或一个小时).在表单上设置 TIME_LIMIT 属性以覆盖它.可能不是这里的情况.

  • 如果在当前会话中没有找到 'csrf_token' 键.您显然可以看到会话令牌,所以它也出来了.

  • 如果 HMAC 签名不匹配;签名基于 'csrf_token' 密钥下会话中设置的随机值、服务器端机密和令牌中的到期时间戳.

排除前三种可能性后,您需要验证第 4 步失败的原因.您可以在 flask_wtf/csrf.py 文件中的 validate_csrf() 函数中调试验证.

对于您的设置,您需要验证会话设置是否正确(尤其是在您不使用默认会话配置的情况下),以及您使用的服务器端密码是否正确.表单本身可能有一个 SECRET_KEY 属性集,但在请求中不稳定,或者应用程序 WTF_CSRF_SECRET_KEY 键已更改(后者默认为 app.secret_key).

CSRF 支持是在 0.9.0 版本中添加的,请查看特定的 CSRF 保护文档 如果你升级了.标准的 Flask-WTF FormincludeCSRF token 作为隐藏字段,渲染隐藏字段足以包含它:

{{ form.hidden_​​tag() }}

A few days ago I have reset my local flask environment without having captured the dependencies via a pip freeze before I deleted it. Hence I had to re-install the latest version of the entire stack.

Now out of the blue I am no longer able to validate with forms. Flask claims CSRF would be missing.

def register():
    form = RegisterForm()
    if form.validate_on_submit():
       ...
    return make_response("register.html", form=form, error=form.errors)

The first time I send a Get I retrieve an empty form.errors as expected. Now I fill out the form and submit it and form.errors is showing: {'csrf_token': [u'CSRF token missing']}

This is so strange. I wonder if Flask-WTF has changed and I am using it wrongly.

I can clearly see the form.CSRF_token exists, so why is it claiming it was missing?

CSRFTokenField: <input id="csrf_token" name="csrf_token" type="hidden" value="1391278044.35##3f90ec8062a9e91707e70c2edb919f7e8236ddb5">

I never touched the working template, but I post it here nonetheless:

{% 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 %}

Is this a new bug?

UPDATE:

I have reinstalled everything and the problem persists.

As Martijn suggested, I am debugging into the the following method in 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'))

The last condition is raising the validation error.

field.data = "1391296243.8##1b02e325eb0cd0c15436d0384f981f06c06147ec"
self.SECRET_KEY = None (? Is this the problem)
self.TIME_LIMIT = 3600

And you were right the HMAC comparison fails....both values are in every time different.

return hmac_compare == hmac_csrf

I have both SECRET_KEY and CSRF_SESSION_KEY in my config defined.

解决方案

The Flask-WTF CSRF infrastructure rejects a token if:

  • the token is missing. Not the case here, you can see the token in the form.

  • it is too old (default expiration is set to 3600 seconds, or an hour). Set the TIME_LIMIT attribute on forms to override this. Probably not the case here.

  • if no 'csrf_token' key is found in the current session. You can apparently see the session token, so that's out too.

  • If the HMAC signature doesn't match; the signature is based on the random value set in the session under the 'csrf_token' key, the server-side secret, and the expiry timestamp in the token.

Having eliminated the first three possibilities, you need to verify why the 4th step fails. You can debug the validation in flask_wtf/csrf.py file, in the validate_csrf() function.

For your setup, you need to verify that the session setup is correct (especially if you don't use the default session configuration), and that you are using the correct server-side secret. The form itself could have a SECRET_KEY attribute set but is not stable across requests, or the app WTF_CSRF_SECRET_KEY key has changed (the latter defaults to the app.secret_key value).

The CSRF support was added in version 0.9.0, do check out the specific CSRF protection documentation if you upgraded. The standard Flask-WTF Form class includes the CSRF token as a hidden field, rendering the hidden fields is enough to include it:

{{ form.hidden_tag() }}

这篇关于由于缺少 CSRF,表单验证失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆