当应用移至 docker 生产环境时,Flask-WTF CSRF 验证失败

Flask-WTF CSRF validation fails when app moved to docker production environment

我刚刚为我一直在开发的 Flask 应用设置生产环境。

这个堆栈是:

Windows Server 2012 R2 
Hyper-V VM 
    - Running Ubuntu 14.04
Docker 1.5 
    - Running Containers: 
        mysql 5.6
        nginx 1.6.3
        uwsgi 2.0.10

所以基本上我在 Ubuntu 中设置了一个静态 IP,端口 80 被转发到 nginx 容器,一个在 nginx 和 uwsgi 容器之间共享的套接字文件的数据量,最后是一个 link 在 mysql 容器和用于数据库通信的 uwsgi 容器之间。

我已经在本地开发环境中的以下实现中使用 CSRF 一段时间了,现在没有任何问题:

from flask_wtf import Form

class UserForm(Form):
    ...

然后在我的模板中:

<form>
    {{ form.hidden_tag() }}
    ...
</form>

然而,当我将我的应用程序原样移动到上面指定的环境时,我得到:

Bad Request

CSRF token missing or incorrect.

在我尝试提交表单时的回应。我使用与 pip 完全相同的 requirements.txt 文件来设置我的 Flask 应用程序。我还验证了 CSRF 令牌确实在页面的 HTML 中。

有人知道为什么会这样吗?

编辑:

回答评论中的问题:我的生产 docker 容器和我的开发本地 virtualenv 中的 Flask-WTF 和 WTForms 的版本是相同的。这是我的需求文件,从我的开发环境中产生并用于在 docker 容器中设置我的应用程序:

Flask==0.10.1
Flask-Login==0.2.11
Flask-Mail==0.9.1
Flask-Migrate==1.2.0
Flask-MySQL==1.2
Flask-Principal==0.4.0
Flask-SQLAlchemy==2.0
Flask-Script==2.0.5
Flask-Security==1.7.4
Flask-WTF==0.10.2
Flask-WhooshAlchemy==0.55a
Jinja2==2.7.3
Mako==1.0.0
MarkupSafe==0.23
PyMySQL==0.6.2
SQLAlchemy==0.7.9
Tempita==0.5.2
WTForms==2.0.1
Werkzeug==0.9.6
Whoosh==2.6.0
alembic==0.6.7
blinker==1.3
chardet==2.2.1
decorator==3.4.0
itsdangerous==0.24
lamson==1.3.4
passlib==1.6.2
py-bcrypt==0.4
pytz==2014.9
sqlalchemy-migrate==0.7.2

也就是说,由于安装了 uWSGI 以及我的烧瓶应用程序,我的 docker 容器中有几个额外的模块。这是额外的。

argparse (1.2.1)
colorama (0.2.5)
docutils (0.12)
html5lib (0.999)
lockfile (0.10.2)
mock (1.0.1)
MySQL-python (1.2.5)
nose (1.3.6)
python-daemon (2.0.5)
python-modargs (1.7)
requests (2.2.1)
six (1.5.2)
urllib3 (1.7.1)
uWSGI (2.0.10)
wheel (0.24.0)
wsgiref (0.1.2)

哇,不止一对。也许我的包裹有冲突?

关于 SECRET_KEY 和 CSRF_SESSION_KEY:我在 config.py 中定义了 SECRET_KEY。我被引导相信,如果不定义 CSRF_SESSION_KEY,它将默认为 SECRET_KEY。尽管如此,我还是继续定义了一个 CSRF_SESSION_KEY,但它似乎没有任何区别。

最后,我研究了 API 从 {{ form.hidden_tag() }} 到 {{ form.csrf_token }} 的变化。他们仍然在最新版本的文档中引用了这两种形式。在 CSRF 页面上,他们有后者,但在快速入门中他们仍然有前者。我不确定这是怎么回事,但为了确定我在 CSRF 页面上实现了如下版本:

初始化.py:

from flask_wtf.csrf import CsrfProtect

CsrfProtect(app)

user_login.html

<form>
    {{ form.csrf_token }}
    ...
</form>

但我还是得到了同样的回应。

正如我之前所说,Flask-WTF 文档无处不在。所以我一直在尝试各种组合。在此页面底部:http://flask-wtf.readthedocs.org/en/latest/csrf.html 他们引用了不正确的导入,所以我替换了我的

from flask_wtf import Form

from flask.ext.wtf import Form

仍然没有骰子。感谢您的评论,给了我更多尝试!

我也只是尝试将所有内容整合到一个 docker 容器中,但我仍然得到相同的结果。

基本上我的开发中有这个 config.py 文件:

SERVER_NAME = 'localhost:5000'

当我将应用程序放到生产环境中时,我不得不将其更改为:

SERVER_NAME = '192.168.1.66'

让应用程序完全显示。但最后我不得不把它完全注释掉。根据我的研究,只有当您将应用程序放在子域上时才有必要,而我不是。

如果有人对这会导致 CSRF 令牌失效的原因有任何更深入的了解,我很想听听。我无法进一步追踪。所以现在,我已经完全删除了它。