使用 Tomcat 允许子域会话 cookie 的最佳方式

Posted

技术标签:

【中文标题】使用 Tomcat 允许子域会话 cookie 的最佳方式【英文标题】:Best way for allowing subdomain session cookies using Tomcat 【发布时间】:2010-09-10 02:31:37 【问题描述】:

默认情况下,tomcat 会为当前域创建会话 cookie。

如果您在 www.example.com,您的 cookie 将为 www.example.com 创建(仅适用于 www.example.com)。而对于 example.com,它将为 .example.com 创建(所需的行为将适用于 example.com 的任何子域以及 example.com 本身)。

我见过一些 Tomcat 阀门,它们似乎拦截了会话 cookie 的创建并使用正确的 .example.com 域创建了一个替换 cookie,但是它们似乎都没有完美地工作,而且它们似乎都离开了现有的cookie 并创建一个新的。这意味着每个请求都会发送两个 JSESSIONID cookie。

我想知道是否有人对此问题有明确的解决方案。

【问题讨论】:

【参考方案1】:

瓣膜技术似乎并非 100% 完美。如果你敢修改Tomcat本身:

catalina.jar 包含以下类:org.apache.catalina.connector.Request

请求有一个方法:

configureSessionCookie(Cookie cookie)

对于我们的环境,最好只对其进行硬编码,但您可以做更多花哨的逻辑:

cookie.setDomain(".xyz.com");

似乎工作得很好。如果这可以在 tomcat 中配置就好了。

【讨论】:

【参考方案2】:

我刚刚经历了所有这些,寻找一个简单的解决方案。我是先从tomcat的角度开始看的。

Tomcat 不能直接访问为会话配置域 cookie,我绝对不想自定义补丁 tomcat 来解决这个问题,如其他一些帖子所示。

由于访问 Servlet 规范中内置的标头和 cookie 的限制,tomcat 中的阀门似乎也是一个问题解决方案。如果 http 响应在传递到您的阀门之前提交,它们也会完全失败。

由于我们通过 Apache 代理我们的请求,然后我转而讨论如何使用 apache 来解决问题。

我首先尝试了 mod_proxy 指令 ProxyPassReverseCookieDomain,但它不适用于 JSESSIONID cookie,因为 tomcat 没有设置域属性,并且如果没有某种域作为 cookie 的一部分,ProxyPassReverseCookieDomain 将无法工作。

我还遇到了一个使用 ProxyPassReverseCookiePath 的黑客攻击,他们正在重写路径以向 cookie 添加域属性,但这对于生产站点来说感觉很混乱。

我终于通过使用上面 Dave 提到的 apache 中的 mod_headers 模块重写响应头来让它工作。

我在虚拟主机定义中添加了以下行:

Header edit Set-Cookie "(JSESSIONID\s?=[^;,]+?)((?:;\s?(?:(?i)Comment|Max-Age|Path|Version|Secure)[^;,]*?)*)(;\s?(?:(?i)Domain\s?=)[^;,]+?)?((?:;\s?(?:(?i)Comment|Max-Age|Path|Version|Secure)[^;,]*?)*)(,|$)" "$1$2; Domain=.example.com$4$5"

以上都应该是配置中的一行。它将任何 JSESSIONID cookie 域属性替换为“.example.com”。如果 JSESSIONID cookie 不包含域属性,则该模式将添加一个值为“.example.com”。作为奖励,此解决方案不会受到阀门的双 JSESSION cookie 问题的影响。

该模式应该适用于 Set-Cookie 标头中的多个 cookie,而不会影响标头中的其他 cookie。通过将模式第一部分中的 JSESSIONID 更改为您想要的任何 cookie 名称,它也应该可以修改以与其他 cookie 一起使用。

我不是 reg-ex 高级用户,所以我确信可以对该模式进行一些优化,但到目前为止它似乎对我们有用。

如果我发现该模式有任何错误,我会更新这篇文章。希望这将阻止你们中的一些人像我一样经历过去几天的挫折。

【讨论】:

【参考方案3】:

这显然是通过 6.0.27 及更高版本中的配置设置支持的:

配置是通过编辑完成的 META-INF/context.xml

https://issues.apache.org/bugzilla/show_bug.cgi?id=48379

【讨论】:

+1 正是我想要的!最后他们包含了补丁。【参考方案4】:

由于会话(及其 Id)基本上只对发布应用程序有价值,您可能宁愿寻找设置额外的 cookie。看看 Tomcats SingleSignOnValve,它为服务器路径“/”而不是“/applicationName”(通常设置 JSESSIONID cookie)提供额外的 Cookie JSESSIONIDSSO(注意 ...SSO)。

使用这样的 Valve,您可以实现所需的任何进程间通信,以便在任意数量的 tomcats/webservers/whatever 上的不同服务器、虚拟主机或 webapps 之间同步任何状态。

您不能为自己的目的使用 tomcats 会话 cookie 的另一个原因是,同一主机上的多个 Web 应用程序具有不同的会话 ID。例如。 “/webapp1”和“/webapp2”有不同的cookies。如果您将“/webapp1”的 cookie 提供给“/webapp2”,这将找不到您引用的会话,使您的会话+cookie 无效并设置自己的新会话。您必须重写所有 tomcats 会话处理以接受外部会话 id 值(安全方面的坏主意)或在应用程序之间共享某个状态。

应将会话处理视为容器(tomcat)业务。无论您需要添加什么,都应该在不干扰容器认为必须执行的操作的情况下添加。

【讨论】:

【参考方案5】:

我在 $DAYJOB 遇到过这个问题。就我而言,我想实现 SSL 登录,然后重定向到非 SSL 页面。 tomcat 的核心问题是方法(从内存中) SessionManager.configureSessionCookie 硬编码您想要访问的所有变量。

我想出了一些想法,包括一个特别令人震惊的 hack,它使用 apache 中的 mod_headers 来根据正则表达式替换重写 cookie。

解决这个问题的决定性方法是向 tomcat 开发人员提交一个补丁,向 SessionManager 类添加可配置参数。

【讨论】:

以上是关于使用 Tomcat 允许子域会话 cookie 的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

如何在同一子域上获取不同的 Django 应用程序以共享会话 cookie?

在根域和一个特定的子域上设置会话 cookie

自定义设计 Cookie

Express 中跨子域的会话

在 Rails 3 中跨多个子域删除会话 Cookie

使子域读取父域会话