代码之家  ›  专栏  ›  技术社区  ›  detly

相同域、不同端口的cherrypy会话

  •  4
  • detly  · 技术社区  · 14 年前

    考虑下面的脚本。它将启动两个子进程,每一个子进程都是一个cherrypy应用程序(点击ctrl+c或系统上的键盘中断组合键来结束这两个子进程)。如果您使用cp 3.0运行它(注意更改“startServer”中的3.0/3.1特定行),请访问:

    http://localhost:15002/

    ……你看到一个空的口述。然后访问:

    http://localhost:15002/set?val=10

    http://localhost:15002/

    ……你会看到新填充的dict。然后访问:

    http://localhost:15012/

    …然后回到

    http://localhost:15002/

    ……一切都没有改变。

    如果你用cp 3.1做同样的事情(记住“startserver”中的行!),当您进入最后一步时,dict现在是空的。这在windows和debian、python 2.5和2.6中都会发生。

    你可以尝试各种方法:切换到文件存储,分离存储路径…它唯一的区别是,会话可能被合并而不是删除。我读过 another post 关于这一点,也有人建议将会话工具配置键放在app config而不是全局配置中,但我认为这与应用程序独立运行的这种用法无关。

    如何使独立的cherrypy应用程序不相互干扰?

    注:我最初是在 CherryPy mailing list 但还没有反应,所以我在这里尝试。我希望没关系。

    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)
    
    2 回复  |  直到 7 年前
        1
  •  3
  •   Denis Otkidach    14 年前

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

    更新 :rfc 2109,第4.3.1节解释集cookie说:

    用户代理单独跟踪 状态信息通过 从每个 源服务器(区别于 名称或IP地址和端口)。

    但标准的解释并不那么明显。这是一个相关的 ticket 在Firefox Tracker中:

    饼干有两个RFC,2109 (用于设置cookie)和2965(用于 SET-CuCIE2

    在RFC 2109第4.3.1节中 解释它声明的集合cookie
    “域默认为请求主机。 “在第2节术语中 声明“请求主机和 请求uri引用 客户端将发送到服务器, 分别是主机(但不是端口) 以及 http的绝对uri(http_url) 请求行。注意 请求主机必须是RFC中的“fqhn”。 第3.3.1节中的2965解释 set-cookie2 it states“域 默认为有效 请求主机。“它还指出” 端口默认行为是 饼干可能是 返回到任何请求端口。“在第一节 术语它陈述“术语 请求主机和请求uri引用 客户的价值观 将分别作为主机(而不是端口)发送到服务器 和 http的绝对uri(http-url)的abs-path部分 请求行。“(就像RFC 2109)

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

        2
  •  1
  •   Michael Mulqueen    7 年前

    DR :更改cherrypy配置参数 tools.sessions.name 对每个应用程序都是独一无二的。

    长回答 :

    我知道这是一个很老的问题,但我认为有一个很简单的答案。下面写的是为了将来的搜索者。

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

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

    解决方案很简单:在cherrypy配置中,可以通过设置 tools.sessions.name工具.sessions.name 到“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