会话混合 - apache httpd 与 mod_jk、tomcat、spring security - 提供其他用户的数据

Posted

技术标签:

【中文标题】会话混合 - apache httpd 与 mod_jk、tomcat、spring security - 提供其他用户的数据【英文标题】:Session mix up - apache httpd with mod_jk, tomcat, spring security - serving data of other user 【发布时间】:2013-01-21 19:30:18 【问题描述】:

最近我们遇到了一个严重的问题,即为一个用户提供了另一个用户的数据。这个问题几乎不可能重现。

我们正在使用 Spring-security 提供的标准登录用户管理,我们确信问题不在于将用户存储在实例变量中或在我们的应用程序中存储类似的并发内容。

我们真的怀疑问题出在 SpringSecurity 或 Tomcat 本身。

我们的前端服务器是 apache httpd,通过 ajp 连接器 (mod_jk) 连接到 tomcat。我们没有做任何负载平衡(httpd 只关心 SSL,一些 url 重写和服务一些 php 模块)

这是我们的设置:

## OS
OS Name:        Linux 
OS Version:     2.6.32-5-686
Architecture:   i386

## Apache httpd
Server version: Apache/2.2.16 (Debian)
Server built:   Sep  4 2011 20:27:42

## mod_jk
mod_jk/1.2.30 (installed via apt-get)

## JVM
JVM Version:    1.6.0_18-b18
JVM Vendor:     Sun Microsystems Inc.

## Tomcat
Server version: Apache Tomcat/6.0.28
Server built:   February 12 2011 1443

我们将此会话中的 httpd / mod_jk 混淆了,因此我们唯一的解决方案是删除 apache httpd。但在我们离开这个流行且广泛使用的配置之前,我们想知道是否有人遇到过类似的问题。

我发现的唯一类似问题是负载平衡或 mod_jk。

你有没有遇到过类似的问题? 任何提示、想法、链接或经验都将受到高度赞赏。 谢谢!

【问题讨论】:

你没疯,这和我遇到的情况几乎一模一样。请看我的问题:***.com/questions/14845493/…。您是否找到过解决方案或有任何其他信息?如果您想在聊天中谈论它,我可以分享尽可能多的信息。 我弄清楚是什么导致了我这个确切的问题。在上面的评论中查看我的自我回答,当您将 Spring 集成到 JSF 项目中时,它与托管 bean 在 JSF 和 Spring 中的工作方式不同有关。 您好 maple_shaft,感谢您的帖子。不幸的是,在我们的例子中,它绝对不是我们代码中的错误。祝你好运。 【参考方案1】:

我在 Glassfish 3.1.2.2 和 Mod_JK 1.2.19 中遇到了同样的问题

您可以使用 JMeter 脚本和良好的断言重现该错误。

这是我讲述这个故事的博文:http://jeecookbook.blogspot.com/2013/07/modjk-session-mixed-between-users.html

使用带有此断言的 Mod_proxy 可以解决问题:不再检测到混合。

【讨论】:

【参考方案2】:

当您集成 JSF 和 Spring 时,JSF 依赖注入与 Spring 依赖注入发生冲突,因此 Spring 重写了处理该问题的 JSF 模块,以仅包装 Spring DI。因此,当我将 JSF ManagedBean 声明为 Session Scoped 时,我还必须给它一个 @Controller 注释,以便它也被识别为 Spring Bean。

For More info, See this.

【讨论】:

【参考方案3】:

到目前为止,我们无法重现该错误,但我们发现有些人在使用 mod_jk 时遇到了同样的问题:

https://issues.apache.org/bugzilla/show_bug.cgi?id=47714 http://grails.1312388.n4.nabble.com/Spring-Security-after-log-in-user-changed-and-session-mixed-up-td4636714.html(在底部)

所以现在我们使用这个设置运行:

JkOptions 禁用重用:http://tomcat.apache.org/connectors-doc/webserver_howto/apache.html worker retries = 0 : http://tomcat.apache.org/connectors-doc/reference/workers.html#Advanced Worker 指令

我们计划将 mod_jk 切换为 mod_proxy_http。

我没有回答这个问题,因为我不能保证(而且没有人面临同样的问题能够保证)解决方案修复了这个错误。

如果有人可以分享任何信息,我将不胜感激!谢谢。

【讨论】:

【参考方案4】:

如果您排除并发会话问题,那么几乎唯一的可能性是您的业务逻辑本身存在缺陷,并为其他用户的数据提供服务。请发布代码示例如何确定“当前用户”,并在以后使用。

编辑:仅在生产中表现出来的错误通常是由竞争条件引起的 (http://en.wikipedia.org/wiki/Race_condition)。确保您的代码尽可能使用局部变量,并在适用的情况下使用锁定/同步。

【讨论】:

您好 rootkit007,也谢谢您。我们的“当前用户”是在标准的 spring-security 样式中获得的:SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 我很确定这不是问题,它必须在某个“更深”的地方,因为该问题仅在上述生产环境中报告,而且它也是几乎不可能复制。 安全上下文存储在会话中。所以它必须是 1. 会话混淆之一(可能包含 jsessionid 的 URL 被复制和粘贴?您使用自定义会话管理器吗?您的 Tomcat 会话是否持久化?) 2. Spring 安全错误(极不可能) 3. 某处的业务逻辑错误 我喜欢带有 jsessionid 的 URL 的想法。但是,如果您使用默认配置,这是不可能的(请参阅文档中的会话固定保护)。 Maksym,您正确地指出默认配置是不可能的。这仍然需要检查,必要时调整配置 正如我所说,用户在不同的计算机上(即使在不同的地理位置),复制粘贴是不可能的。业务逻辑错误的可能性极小,我们在所有产品应用程序中都使用相同的代码,并且仅在该设置中我们才报告了此错误。【参考方案5】:

可能的问题之一可能是第二次登录尝试。 考虑以下情况:

用户打开带有两个登录表单的两个浏览器选项卡。 选项卡 1:以 user_1 身份登录。将一些数据加载到 HTTP 会话中。 选项卡 2:以 user_2 身份登录。将一些数据加载到 HTTP 会话中。

在大多数浏览器中,它将是相同的 HTTP 会话。因此,实际上您将来自 user_1 和 user_2 的数据组合在一个 HTTP 会话中。任何使用会话对象的页面都可能受到影响。

你有两个选择:

防止出现这种情况。检测第二次登录尝试并要求用户先注销。使用 Spring Security 很容易,请参见下面的代码。 如果您绝对需要每个浏览器选项卡一个帐户,那么您可以将会话数据存储在每个用户名的映射中。

感谢Concurrent Session Control fetaure,您可以防止第二次登录尝试:

<http>
    ...
    <session-management>
        <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
    </session-management>
</http>

它已经在你的应用程序中完成了吗?

【讨论】:

您好 Maksym,感谢您的回答,但这绝对不是我们的问题。 User_1 显示的是 User_2 的数据,用户在不同的浏览器上,甚至在不同的地理位置。恐怕这个问题更复杂。

以上是关于会话混合 - apache httpd 与 mod_jk、tomcat、spring security - 提供其他用户的数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在混合 Apache 和 Tomcat 环境中保持会话

apache tomcat + apache httpd + mod_proxy + mod_rewrite + 表单发布数据

apache httpd ProxyRequests設置

关于Apache (httpd)服务器防DDOS模块mod_evasive的使用说明

使用 mod_jk 和 Apache httpd 时为 Tomcat 的 404 页面使用自定义错误页面

如果 .htaccess 使用 mod_rewrite,则 Apache httpd.conf mod_rewrite 取消