Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/apache/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
由于会话重置,Apache Flask中的CSRF令牌不匹配_Apache_Python 2.7_Flask_Csrf_Flask Wtforms - Fatal编程技术网

由于会话重置,Apache Flask中的CSRF令牌不匹配

由于会话重置,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令牌不匹配。我在

我有一个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令牌
不匹配。我在视图开始时记录
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)