关于Java:使用Tomcat允许子域会话Cookie的最佳方法

关于Java:使用Tomcat允许子域会话Cookie的最佳方法

Best way for allowing subdomain session cookies using Tomcat

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

如果您在www.example.com上,则将为www.example.com创建cookie(仅在www.example.com上有效)。 而example.com将为.example.com创建(期望的行为,它将在example.com的任何子域以及example.com本身上都起作用)。

我见过一些Tomcat阀门,它们似乎在拦截会话cookie的创建并使用正确的.example.com域创建替换cookie,但是它们似乎都无法正常工作,它们似乎都保留了现有的cookie,只是 创建一个新的。 这意味着每个请求都将发送两个JSESSIONID cookie。

我想知道是否有人可以解决这个问题。


显然可以通过6.0.27及更高版本中的配置设置来支持此功能:

Configuration is done by editing
META-INF/context.xml

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


我刚刚完成了所有这些工作,以寻找简单的解决方案。我首先从雄猫的角度开始研究它。

Tomcat不允许直接访问为会话配置域cookie,而且我绝对不希望自定义补丁tomcat来解决该问题,如其他一些文章所示。

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

由于我们通过Apache代理请求,因此我转而研究如何使用apache来解决问题。

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

我还遇到了一个使用ProxyPassReverseCookiePath的黑客,他们在其中重写了将域属性添加到cookie的路径,但是这对于生产站点来说是一种混乱的方式。

我终于通过使用apache中的mod_headers模块重写响应标头使其工作,如上文Dave所述。

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

1
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"

上面的内容在配置中应该都是一行。它将用" .example.com"替换任何JSESSIONID cookie域属性。如果JSESSIONID cookie不包含domain属性,则该模式将添加一个值为" .example.com"的cookie。另外,此解决方案不会遭受阀门的双重JSESSION cookie问题的困扰。

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

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

如果发现该模式有任何错误,我将更新此帖子。希望这将使你们中的一些人不必像我一样经历最后几天的挫折。


阀门技术似乎并非100%完美。如果您敢于修改Tomcat本身:

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

该请求具有以下方法:

1
configureSessionCookie(Cookie cookie)

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

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

似乎工作正常。如果可以在tomcat中配置,那就太好了。


由于会话(及其ID)基本上仅被考虑用于发布应用程序,因此您可能希望设置其他cookie。看一下Tomcats SingleSignOnValve,为服务器路径" /"而不是" / applicationName"提供额外的Cookie JSESSIONIDSSO(请注意... SSO)(因为通常会设置JSESSIONID cookie)。

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

您不能出于自己的目的使用tomcats会话cookie的另一个原因是,同一主机上的多个Web应用程序具有不同的会话ID。例如。" / webapp1"和" / webapp2"有不同的Cookie。如果将" / webapp1"的cookie提供给" / webapp2",则将找不到您引用的会话,从而使session + cookie无效并设置自己的新cookie。您必须重写所有tomcats会话处理,才能接受外部会话ID值(出于安全考虑,这是个坏主意),或者在应用程序之间共享特定状态。

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


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

我提出了一些想法,包括一个特别糟糕的黑客,该黑客在apache中使用mod_headers来基于正则表达式替换来重写cookie。

解决此问题的权威方法是向tomcat开发人员提交补丁,该补丁将可配置参数添加到SessionManager类。


推荐阅读