当前的 cookie 规范是 RFC 6265,它替换了 RFC 2109 和 RFC 2965(这两个 RFC 现在都标记为“历史”),并正式确定了 cookie 实际使用的语法。它明确指出:
简介 ... 由于历史原因,cookie 包含许多安全和隐私方面的缺陷。例如,服务器可以指示给定的 cookie 用于“安全”连接,但 Secure 属性在存在活动网络攻击者的情况下不提供完整性。类似地,给定主机的 cookie 在该主机上的所有端口之间共享,即使 Web 浏览器使用的通常的“同源策略”会隔离通过不同端口检索的内容。
并且:
8.5。弱机密性 Cookie 不提供端口隔离。如果运行在一个端口上的服务可以读取 cookie,则运行在同一服务器的另一个端口上的服务也可以读取 cookie。如果 cookie 可由一个端口上的服务写入,则该 cookie 也可由运行在同一服务器的另一个端口上的服务写入。出于这个原因,服务器不应该在同一主机的不同端口上运行相互不信任的服务并使用 cookie 来存储安全敏感信息。
根据 RFC2965 3.3.1(浏览器可能会或可能不会遵循),除非通过 Set-Cookie
标头的 port
参数明确指定端口,否则 cookie 可能会或可能不会发送到任何端口。
Google 的 Browser Security Handbook 说:默认情况下,cookie 范围仅限于当前主机名上的所有 URL - 并且不绑定到端口或协议信息。 以及稍后的一些行 没有办法将 cookie 限制为仅单个 DNS 名称 [...] 同样,无法将它们限制为特定端口。(另外,请记住,IE 不会将端口号计入其同源政策完全。)
因此,在这里依赖任何明确定义的行为似乎并不安全。
Set-Cookie
标头中的 Port
参数(因为实际上几乎没有人实际使用它),并且非常明确地表明同一主机上的 cookie 不再可以通过端口区分。
这是一个非常古老的问题,但我想我会添加一个我使用的解决方法。
我的笔记本电脑上运行了两项服务(一个在端口 3000 上,另一个在 4000 端口上)。当我在 (http://localhost:3000
和 http://localhost:4000
) 之间跳转时,Chrome 会传入同一个 cookie,每个服务都不会理解 cookie 并生成一个新的。
我发现如果我访问 http://localhost:3000
和 http://127.0.0.1:4000
,问题就消失了,因为 Chrome 为 localhost 和 127.0.0.1 保留了一个 cookie。
同样,此时可能没有人关心,但这对我的情况很容易且有帮助。
localhost
上的 cookie 不能与 127.0.0.1
共享,反之亦然。但是同一主机/域上的 cookie,无论端口如何,都是可共享的。
这是 cookie SOP(Same Origin Policy)中的一个很大的灰色区域。
理论上,您可以在域中指定端口号,cookie 不会被共享。实际上,这不适用于多个浏览器,您会遇到其他问题。因此,这仅在您的网站不面向公众并且您可以控制要使用的浏览器时才可行。
更好的方法是为同一个 IP 获取 2 个域名,而不依赖于 cookie 的端口号。
解决此问题的另一种方法是使会话 cookie 的名称与端口相关。例如:
mysession8080 用于在端口 8080 上运行的服务器
mysession8000 用于在端口 8000 上运行的服务器
您的代码可以访问网络服务器配置以找出您的服务器使用的端口,并相应地命名 cookie。
请记住,您的应用程序将同时接收两个 cookie,并且您需要请求与您的端口对应的一个。
cookie 名称中不需要有确切的端口号,但这更方便。
通常,cookie 名称可以对特定于您使用的服务器实例的任何其他参数进行编码,因此可以通过正确的上下文对其进行解码。
在 IE 8 中,cookie(仅针对 localhost 进行验证)在端口之间共享。在 FF 10 中,它们不是。
我已经发布了这个答案,以便读者至少有一个具体的选项来测试每个场景。
我在同一台机器上运行(并尝试调试)两个不同的 Django 应用程序时遇到了类似的问题。
我用这些命令运行它们:
./manage.py runserver 8000
./manage.py runserver 8001
当我登录第一个然后在第二个登录时,我总是退出第一个,反之亦然。
我在我的 /etc/hosts 上添加了这个
127.0.0.1 app1
127.0.0.1 app2
然后我使用以下命令启动了这两个应用程序:
./manage.py runserver app1:8000
./manage.py runserver app2:8001
问题解决了 :)
127.0.0.1:8000
用于一个,localhost:8000
用于第二个,可能 ::1:8000
(可能是 [::1]:8080
)用于第三个,而无需触摸主机文件。
::1 app1 app2 app3 app4 app5 appN
这是可选的。
可以指定端口,因此 cookie 可以是特定于端口的。没有必要,Web 服务器/应用程序必须关心这一点。
来源:German Wikipedia article,RFC2109,第 4.3.1 章
/etc/hosts
可用于为127.0.0.1
创建比localhost
更多的 cookie 域