我有一个在开发环境中完美运行的 CSRF 保护表单示例(Flask 使用 app.run
运行服务器本身)但是当我通过 mod_wsgi
运行应用程序时失败在 Apache 。我使用的版本是:
Server version: Apache/2.4.4 (Unix)
Python 2.7.3
Flask==0.10.1
Flask-WTF==0.9.5
WTForms==2.0
Flask-KVSession==0.4
simplekv==0.8.4
它失败的原因是
csrf_token
表单验证期间不匹配。我记录了 flask.session
的内容和 flask.request.form
在 View 的开头和 session 的内容再次在 View 的结尾。在开发模式下csrf_token
的内容在 session 中在多个请求中保持不变,例如,<KVSession {'csrf_token': '79918c1e3191e4d4fe89a9499f576404a18be8e4'}>
在这两种情况下,表格的内容都会正确传输,例如,
ImmutableMultiDict([('csrf_token', u'1403778775.86##34f1447f1b8c78808f4e71f2ff037bcd1df41dcd'),
('time', u'8'), ('submit', u'Go'), ('dose', u'Low')])
当我通过 Apache 运行我的应用程序时,每次请求都会重置 session 内容。在 View 的开头, session 内容为空:
<KVSession {}>
然后每次都会设置一个新的 token ,这会导致不匹配。目前,我的
__init__.py
模块如下所示:from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from simplekv.memory import DictStore
from flaskext.kvsession import KVSessionExtension
app = Flask(__name__)
app.config.from_object("myapp.config.Config")
db = SQLAlchemy(app)
store = DictStore()
KVSessionExtension(store, app)
from . import views
我删除了
KVSession
声明并没有改变问题。所以我认为服务器端 session 不是罪魁祸首。是的,我设置了
SECRET_KEY
至os.urandom(128)
在配置中。我的
httpd.conf
的相关(我认为)部分是:Listen url.com:8090
<VirtualHost url.com:8090>
# --- Configure VirtualHost ---
LogLevel debug
ServerName url.com
DocumentRoot /path/to/flaskapp/htdocs
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /path/to/flaskapp/htdocs/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Require all granted
</Directory>
# --- Configure WSGI Listening App(s) ---
WSGIDaemonProcess mysite user=me group=us processes=2 threads=10
WSGIScriptAlias / /path/to/flaskapp/wsgi/wsgi.py
<Directory /path/to/flaskapp/wsgi/>
WSGIProcessGroup mysite
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Require all granted
</Directory>
# --- Configure Static Files ---
Alias /static/ /path/to/flaskapp/htdocs/static/
Alias /tmp/ /path/to/flaskapp/htdocs/tmp/
</VirtualHost>
有谁知道 Apache 设置或 mod_wsgi 与 Flask 交互可能导致 session 在请求之间不持久?
最佳答案
这里发生的是您使用 Flask-KVSession
存储 session 。 ,并提供基于内存的 DictStore
作为存储:
from simplekv.memory import DictStore
store = DictStore()
KVSessionExtension(store, app)
根本原因
在单线程环境中,这将起作用。但是,当多个进程起作用时,它们不会共享相同的内存,并且
DictStore
的多个实例被创建,每个进程一个。结果,当两个后续请求由两个不同的进程提供服务时,第一个请求将无法将 session 更改传递给下一个请求。或者,甚至更短:两个进程 = 两个 CSRF token 。不好。
解决方案
使用持久存储。这就是我使用的:
def configure_session(app):
with app.app_context():
if config['other']['local_debug']:
store = simplekv.memory.DictStore()
else:
store = simplekv.db.sql.SQLAlchemyStore(engine, metadata, 'sessions')
# Attach session store
flask_kvsession.KVSessionExtension(store, app)
关于apache - 由于 session 重置,Apache Flask 中的 CSRF token 不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24427274/