繁体   English   中英

针对相同域,不同端口的CherryPy会话

[英]CherryPy sessions for same domain, different port

考虑下面的脚本。 它将启动两个子进程,每个子进程一个CherryPy应用程序(按Ctrl + C或系统上的任何KeyboardInterrupt组合来结束它们)。 如果您使用CP 3.0运行它(注意更改“StartServer”中的3.0 / 3.1特定行),请访问:

HTTP://本地主机:15002 /

......你看到一个空洞的词典。 然后访问:

HTTP://本地主机:15002 /组VAL = 10

HTTP://本地主机:15002 /

......你看到新填充的字典。 然后访问:

HTTP://本地主机:15012 /

......然后回去

HTTP://本地主机:15002 /

......没有任何改变。

如果你用CP 3.1尝试相同的事情(记住“StartServer”中的行!),当你​​到达最后一步时,dict现在是空的。 这种情况发生在Windows和Debian,Python 2.5和2.6中。

您可以尝试各种各样的事情:更改为文件存储,分离存储路径......它唯一的区别是会话可能会合并而不是擦除。 我已经阅读了另一篇关于此的帖子 ,并且有一个建议将会话工具配置键放在app配置中而不是全局配置中,但我认为这与应用独立运行的用法无关。

如何让独立的CherryPy应用程序互不干扰?

注意:我最初在CherryPy邮件列表上问过这个,但还没有回复,所以我在这里尝试。 我希望没关系。

import os, os.path, socket, sys
import subprocess
import cgi

import cherrypy

HTTP_PORT = 15002
HTTP_HOST = "127.0.0.1"

site1conf = {
    'global' : {
        'server.socket_host' : HTTP_HOST,
        'server.socket_port' : HTTP_PORT,
        'tools.sessions.on' : True,
#        'tools.sessions.storage_type': 'file',
#        'tools.sessions.storage_path': '1',
#        'tools.sessions.storage_path': '.',
        'tools.sessions.timeout' : 1440}}

site2conf = {
    'global' : {
        'server.socket_host' : HTTP_HOST,
        'server.socket_port' : HTTP_PORT + 10,
        'tools.sessions.on' : True,
#        'tools.sessions.storage_type': 'file',
#        'tools.sessions.storage_path': '2',
#        'tools.sessions.storage_path': '.',
        'tools.sessions.timeout' : 1440}}


class Home(object) :

    def __init__(self, key):
        self.key = key

    @cherrypy.expose
    def index(self):
        return """\
<html>
<body>Session:
<br>%s
</body>
</html> """ % cgi.escape(str(dict(cherrypy.session)))

    @cherrypy.expose
    def set(self, val):
        cherrypy.session[self.key.upper()] = val
        return """\
<html>
<body>Set %s to %s</body>
</html>""" % (cgi.escape(self.key), cgi.escape(val))

def StartServer(conf, key):
    cherrypy.config.update(conf)

    print 'Starting server (%s)' % key
    cherrypy.tree.mount(Home(key), '/', {})

    # Start the web server.
    #### 3.0
    # cherrypy.server.quickstart()
    # cherrypy.engine.start()
    ####

    #### 3.1
    cherrypy.engine.start()
    cherrypy.engine.block()
    ####

def Main():
    # Start first webserver
    proc1 = subprocess.Popen(
        [sys.executable, os.path.abspath(__file__), "1"])
    proc2 = subprocess.Popen(
        [sys.executable, os.path.abspath(__file__), "2"])

    proc1.wait()
    proc2.wait()

if __name__ == "__main__":

    print sys.argv

    if len(sys.argv) == 1:
        # Master process
        Main()
    elif(int(sys.argv[1]) == 1):
        StartServer(site1conf, 'magic')
    elif(int(sys.argv[1]) == 2):
        StartServer(site2conf, 'science')
    else:
        sys.exit(1)

存储会话标识符的cookie绑定到主机,而不是主机+端口。 当您访问第一个站点时,您将获得3.1中的新会话ID (但不是3.0) ,然后您填写会话数据并可以看到它。 之后你用其会话ID转到其他端口,但现在它无效(我相信你可以在登录调试模式下看到这一点)。 所以服务器会向您发送新的会话ID。 现在您返回到第一台服务器,您的标识符再次无效,因此您将获得新的标识符。 当然,会话中没有这个新标识符的数据。

更新 :RFC 2109,第4.3.1节解释Set-Cookie说:

用户代理通过来自每个源服务器的Set-Cookie响应头(通过名称或IP地址和端口区分)保持对到达的状态信息的单独跟踪。

但标准的解释并不那么明显。 以下是firefox跟踪器相关票据的引用:

Cookie有两个RFC,2109(用于set-cookie)和2965(用于set-cookie2)

在RFC 2109的4.3.1解释Set-Cookie中,它说明了这一点
“域默认为请求主机。”在第2节“术语”中,它声明“术语请求主机和请求URI指的是客户端将分别作为主机(但不是端口)发送到服务器的值,并且HTTP请求行的absoluteURI(http_URL)的abs_path部分。请注意,request-host必须是FQHN。“ 在3.3.1节解释Set-Cookie2的RFC 2965中,它指出“域默认为有效请求 - 主机。”它还指出“端口默认行为是cookie可以返回到任何请求端口。”并在节中1 TERMINOLOGY它声明“术语request-host和request-URI是指客户端将分别作为HTTP请求行的absoluteURI(http_URL)的主机(但不是端口)和abs_path部分发送给服务器的值。“(就像RFC 2109一样)

我对这些的解释是端口号不应该用于记录cookie域,除非set-cookie2头明确定义端口号。

TL; DR :将CherryPy配置参数tools.sessions.name更改为每个应用程序的唯一内容。

答案很长

我知道这是一个非常古老的问题,但我认为有一个非常简单的答案。 为了未来的搜索者的利益写下面。

CherryPy使用cookie来查找会话。 默认情况下,这称为“session_id”,并且随机十六进制字符串作为其值。 如果给CherryPy一个它无法识别的session_id,它会生成一个新的session_id。 这是一种防止会话固定的措施。

当您在同一个域上有两个应用程序时。 它们都使用相同的cookie名称(即“session_id”),但都不识别另一个的session_id,因此它们用新的覆盖它。 因此从一个应用程序移动到另一个应用程序会使会话无效。

解决方案很简单:在CherryPy配置中,您可以通过将tools.sessions.name设置为“session_id”以外的其他内容来覆盖session_id名称,例如“myapp_session_id”和“myotherapp_session_id”。

您需要确保会话存储是正确的,因为您已正确识别。

从上面的例子中,你可以这样做:

site1conf = {
    'global': {
        'server.socket_host': HTTP_HOST,
        'server.socket_port': HTTP_PORT,
        'tools.sessions.on': True,
        'tools.sessions.storage_type': 'file',
        'tools.sessions.storage_path': '/tmp/site1_sessions/',
        'tools.sessions.name': 'site1_session_id',
        'tools.sessions.timeout': 1440
    }
}
site2conf = {
    'global': {
        'server.socket_host': HTTP_HOST,
        'server.socket_port': HTTP_PORT + 10,
        'tools.sessions.on': True,
        'tools.sessions.storage_type': 'file',
        'tools.sessions.storage_path': '/tmp/site2_sessions/',
        'tools.sessions.name': 'site2_session_id',
        'tools.sessions.timeout': 1440
    }
}

注意:在我自己使用CherryPy 10.0.0的应用程序中,我在应用程序级别和路径级别使用了此配置选项。 我没有使用旧版本的CherryPy对此进行测试,但是看一下源代码,它看起来已经有十多年了。

自写这篇文章以来,我已经对CherryPy的相关文档进行了更新,包括: http//docs.cherrypy.org/en/latest/pkg/cherrypy.lib.html#session-fixation-protection

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM