Python 由于缺少CSRF,表单验证失败

Python 由于缺少CSRF,表单验证失败,python,forms,flask,flask-wtforms,Python,Forms,Flask,Flask Wtforms,几天前,我重置了本地flask环境,但在删除它之前,我没有通过pip freeze捕获依赖项。因此,我不得不重新安装整个堆栈的最新版本 现在出乎意料的是,我再也不能用表单验证了。Flask声称CSRF将丢失 def register(): form = RegisterForm() if form.validate_on_submit(): ... return make_response("register.html", form=form, error=

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

现在出乎意料的是,我再也不能用表单验证了。Flask声称CSRF将丢失

def register():
    form = RegisterForm()
    if form.validate_on_submit():
       ...
    return make_response("register.html", form=form, error=form.errors)
第一次发送
Get
时,我检索到一个空的
表单。错误与预期一致。
现在我填写表单并提交,然后
表单。错误显示:
{'csrf_-token':[u'csrf-token missing']}

这太奇怪了。我想知道烧瓶WTF是否已更改,我是否错误地使用了它

我可以清楚地看到
表单。CSRF_令牌
存在,为什么它声称它丢失了

CSRFTokenField: <input id="csrf_token" name="csrf_token" type="hidden" value="1391278044.35##3f90ec8062a9e91707e70c2edb919f7e8236ddb5">
最后一个条件是引发验证错误

field.data = "1391296243.8##1b02e325eb0cd0c15436d0384f981f06c06147ec"
self.SECRET_KEY = None (? Is this the problem)
self.TIME_LIMIT = 3600
你是对的,HMAC比较失败……两个值每次都不同

return hmac_compare == hmac_csrf

我在配置中定义了密钥和CSRF会话密钥。

如果出现以下情况,Flask WTF CSRF基础结构将拒绝令牌:

  • 令牌不见了。这里不是这样,您可以在表单中看到令牌

  • 它太旧(默认过期时间设置为3600秒或一小时)。在表单上设置
    时间限制
    属性以覆盖此限制。这里可能不是这样

  • 如果在当前会话中未找到
    'csrf\u令牌'
    密钥。很明显,您可以看到会话令牌,因此也不存在了

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

排除了前三种可能性后,您需要验证第四步失败的原因。您可以在
validate\u csrf()
函数的
flask\u wtf/csrf.py
文件中调试验证

对于您的设置,您需要验证会话设置是否正确(特别是在您不使用默认会话配置的情况下),以及您是否使用了正确的服务器端机密。表单本身可能设置了
SECRET\u KEY
属性,但在请求之间不稳定,或者app
WTF\u CSRF\u SECRET\u KEY
已更改(后者默认为)

CSRF支持是在版本0.9.0中添加的,如果升级了,请查看具体的。标准Flask WTF
表单
类将CSRF令牌作为隐藏字段包含,呈现隐藏字段足以包含它:

{{ form.hidden_tag() }}

经过将近一天的努力,我终于发现了这个问题( 非常感谢Martijn的帮助

实际问题在于最新的csrf烧瓶的工作方式。制造商已经对其进行了彻底检修

您必须将模板中的所有
{{form.hidden_tag()}}
替换为

现在,您必须通过添加
CsrfProtect(app)
来明确启用CSRF保护

现在很明显,这反映了这一点,但我不知道这已经发生了变化,我正在追逐鬼魂


在没有通知开发人员的情况下使用不推荐的功能是一个大问题。现在升级到最新版本的任何人都会像我一样追逐鬼魂。但这也是我的错,没有拍摄我的依赖项的快照。这是一个惨痛的教训。

对我来说,问题并不是来自Flask WTF配置不当红色,或缺少标记。它来自环境变量

如果您的Flask服务器没有在本地主机上运行,那么为了使Flask正常工作,您需要设置一个
server\u NAME
环境变量。您可能忘记了在某个地方修改
server\u NAME

例如,在
config/settings.py
中可以有类似的内容:

SERVER_NAME = 'my-domain.com'

有关更多信息,请在创建应用程序时查看:

from flask_wtf.csrf import CsrfProtect

csrf = CsrfProtect()

app = Flask(__name__)   

...

csrf.init_app(app)

...

您是否接受Cookie?CSRF体系结构要求会话中存在
CSRF\u令牌
值且该值有效;它是一个随机值,用于签署令牌,并在发布时用于验证CSRF令牌与表单(以及服务器端机密)是的,Firefox和Chrome都没有阻止cookie。我不明白。因此,为了验证,您确实看到了名为
session
set的cookie(前提是您没有将
session\u cookie\u NAME
设置为其他名称)?是的。在Eclipse的调试观察列表下,当我进入
会话时,我得到以下信息:
本地代理:
我有这个问题很久了,意识到这是我的
会话\u COOKIE\u SECURE=True
应用程序设置。希望这对其他人有帮助。谢谢Martijn,非常感谢你的帮助。请你看看我的设置日期问题?在我的例子中,应用程序在本地计算机上运行正常,但在托管时崩溃。这是由于作者描述的会话设置不正确。如果遇到相同问题,请在flask应用程序中设置一个常量密钥。您不必替换
隐藏的标签()
,但
CsrfProtect(应用程序)
当然是必需的。另外,
self.SECRET\u KEY
是每个表单的机密,当它设置为
None
时,使用应用程序机密。感谢Martijn,我发现了另一个问题。我正在GAE上部署它。似乎
flask\u wtf
flask DebugToolbar
冲突。当我禁用
toolbar=DebugToolbarExtension时(应用程序)
,CSRF正在开发人员环境中工作。但只有那些使用
flask appengine模板的开发人员受到影响。
:)有趣。我当前的项目正在GAE上使用Flask,但我没有使用任何模板,也没有使用Flask DebugToolbar。如果我使用,我会注意任何问题。我现在有几个项目同时使用调试工具栏和CSRF保护窗体。如果您只使用FlaskForm窗体,则根本不需要CSRFProtect
SERVER_NAME = 'my-domain.com'
from flask_wtf.csrf import CsrfProtect

csrf = CsrfProtect()

app = Flask(__name__)   

...

csrf.init_app(app)

...