由于会话重置,Apache Flask中的CSRF令牌不匹配
我有一个CSRF保护表单的示例,它在开发环境中运行得非常好(Flask使用由于会话重置,Apache Flask中的CSRF令牌不匹配,apache,python-2.7,flask,csrf,flask-wtforms,Apache,Python 2.7,Flask,Csrf,Flask Wtforms,我有一个CSRF保护表单的示例,它在开发环境中运行得非常好(Flask使用app.run)运行服务器本身,但在Apache中通过mod_wsgi运行应用程序时失败。我使用的版本是: 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\u令牌不匹配。我在
app.run
)运行服务器本身,但在Apache中通过mod_wsgi
运行应用程序时失败。我使用的版本是:
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\u令牌
不匹配。我在视图开始时记录flask.session
和flask.request.form
的内容,并在视图结束时再次记录会话的内容。在开发模式下,会话中的csrf_令牌的内容在多个请求中保持不变,例如
<KVSession {'csrf_token': '79918c1e3191e4d4fe89a9499f576404a18be8e4'}>
当我通过Apache运行我的应用程序时,会话内容会随着每个请求而重置。在视图的开头,会话内容为空:
<KVSession {}>
我删除了KVSession
语句,但这并没有改变问题。因此,我认为服务器端会话不是罪魁祸首
是的,我已经在配置中将密钥设置为os.uradom(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>
Listen url.com:8090
#---配置虚拟主机---
日志级调试
ServerName url.com
DocumentRoot/path/to/flaskapp/htdocs
选项如下符号链接
不允许超限
选项索引跟随符号链接多视图
不允许超限
要求所有授权
#---配置WSGI侦听应用程序---
WSGIDaemonProcess mysite user=me group=us processs=2线程=10
WSGIScriptAlias//path/to/flaskapp/wsgi/wsgi.py
WSGIProcessGroup mysite
WSGIApplicationGroup%{GLOBAL}
WSGIScript正在重新加载
要求所有授权
#---配置静态文件---
别名/static//path/to/flaskapp/htdocs/static/
别名/tmp//path/to/flaskapp/htdocs/tmp/
有人知道Apache设置或mod_wsgi与Flask交互可能导致会话在请求之间无法持久化吗?这里发生的情况是,您使用Flask KVSession
存储会话,并提供基于内存的DictStore
作为存储:
from simplekv.memory import DictStore
store = DictStore()
KVSessionExtension(store, app)
根本原因
在单线程环境中,这将起作用。但是,当多个进程开始工作时,它们不共享相同的内存,并且会创建多个DictStore
实例,每个进程一个。因此,当两个后续请求由两个不同的进程提供服务时,第一个请求将无法将会话更改传递给下一个请求
或者,甚至更短:两个进程=两个CSRF令牌。不太好
解决方案
使用持久存储。这就是我使用的:
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)
您的mod_wsgi配置是什么样子的?@SeanVieira I添加了部分httpd.conf
。我只加载mod_wsgi
模块(LoadModule wsgi\u module lib/httpd/mod_wsgi.so
)但没有更改其配置。我的猜测是,您每次都会被两个不同的进程处理,因为您在加载代码时使用os.uradom
来创建密钥,这会导致每个进程都有不同的密钥,这不是您想要的。要确认,请尝试硬编码的密钥,看看这是否解决了问题。如果有,您可以在部署时生成一个密钥,并将其存储在磁盘或内存中,然后将其引用到生产密钥中@SeanVieira你至少了解了一些事情。固定密钥并不能解决我的问题,在请求开始时会话仍然是空的。将配置中的进程数减少到1
确实解决了这个问题。我将进一步阅读文档,感谢您提供的链接。我没有立即进行测试的所有设置。不过,这听起来很合理。谢谢你的解释。
from simplekv.memory import DictStore
store = DictStore()
KVSessionExtension(store, app)
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)