考虑下面的脚本。它将启动两个子进程,每个子进程一个CherryPy应用程序(按Ctrl + C或系统上的任何KeyboardInterrupt组合来结束它们)。如果您使用CP 3.0运行它(注意更改“StartServer”中的3.0 / 3.1特定行),请访问:
...你看到一个空的字典。然后访问:
http://localhost:15002/set?val=10
...你看到新填充的字典。然后访问:
...然后回到
......一切都没有改变。
如果你对CP 3.1尝试相同的事情(记住“StartServer”中的行!),当你到达最后一步时,dict现在是空的。这种情况发生在Windows和Debian,Python 2.5和2.6中。
您可以尝试各种各样的事情:更改为文件存储,分离存储路径......它唯一的区别是会话可能会合并而不是擦除。我也已经阅读了another post,并建议将会话工具配置密钥放在应用程序配置而不是全局配置中,但我不认为这与应用程序的用法相关独立运作。
如何让独立的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)
答案 0 :(得分:3)
存储会话标识符的cookie绑定到主机,而不是主机+端口。当您访问第一个网站时,您在3.1(但不是3.0)中获得新会话ID ,然后您填写会话数据并可以看到它。之后你用其会话ID转到其他端口,但现在它无效(我相信你可以在登录调试模式下看到这一点)。所以服务器会向您发送新的会话ID。现在您返回到第一台服务器,您的标识符再次无效,因此您将获得新的标识符。当然,会话中没有这个新标识符的数据。
更新:RFC 2109,第4.3.1节解释Set-Cookie说:
用户代理保持单独的跟踪 通过的国家信息 每个Set-Cookie响应头 原始服务器(区别于 名称或IP地址和端口)。
但标准的解释并不那么明显。以下是firefox跟踪器中相关ticket的引用:
Cookie有两个RFC,2109 (对于set-cookie)和2965(For 设定COOKIE2)
在RFC 2109的4.3.1节中 解释它所声明的Set-Cookie “域默认为请求主机。 “而在第2节术语中 陈述“条款请求 - 主机和 request-URI引用的值 客户端将发送到服务器, 分别是主机(但不是端口) 和abs_path部分 HTTP的absoluteURI(http_URL) 请求行。注意 request-host必须是FQHN。“在RFC中 第3.3.1节中的2965解释 Set-Cookie2它表示“域名 默认为有效 请求主机。 “它还说” 端口默认行为是a cookie可能是 返回任何请求端口。 “并在第1节 术语它陈述“条款 request-host和request-URI参考 客户的价值观 将分别作为主机(但不是端口)发送到服务器 和 abs_path部分HTTP的absoluteURI(http_URL) 请求行。 “(就像RFC 2109一样)
我对这些的解释是 端口号不应该用于 记录cookie域,除非a set-cookie2标头明确定义 端口号。
答案 1 :(得分:1)
TL; DR :将CherryPy配置参数tools.sessions.name
更改为每个应用程序的唯一内容。
答案很长:
我知道这是一个非常古老的问题,但我认为有一个非常简单的答案。写下面是为了未来的搜索者的利益。
CherryPy使用cookie来查找会话。默认情况下,这称为&#34; session_id&#34;并且有一个随机的十六进制字符串作为其值。如果为CherryPy提供了一个它无法识别的session_id,它会生成一个新的session_id。这是一种防止会话固定的措施。
当您在同一个域中有两个应用程序时。它们都使用相同的cookie名称(即&#34; session_id&#34;),但都不识别另一个的session_id,因此它们用新的覆盖它。因此,从一个应用程序移动到另一个应用程序会使会话无效。
解决方案很简单:在CherryPy配置中,您可以通过将tools.sessions.name
设置为&#34; session_id&#34;以外的其他内容来覆盖session_id名称,例如&#34; myapp_session_id&#34;和&#34; myotherapp_session_id&#34;。
您需要确保会话存储是独立的,因为您已正确识别。
从上面的示例中,您可以执行以下操作:
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