防止同一服务器会话上的多个浏览器会话

时间:2010-02-01 17:14:45

标签: language-agnostic session

我确信我们已经完成了所有工作,或者知道已经紧密绑定到服务器会话的Web应用程序(特别是在企业中)。在这些情况下,如果打开多个浏览器会话并使用相同的服务器会话cookie,则会话可能会损坏。我们已经检查了所有选项,发现前进的最佳方法是阻止使用共享服务器会话cookie的多个浏览器会话。

当用户在IE中执行New Window - Ctrl+N或在其他浏览器中执行“重复选项卡”时,这只是一个问题。基本上我们最终会有两个活动的浏览器会话共享相同的cookie。

所以,为了阻止这种情况(因为它可能是无意的)我已经着手制定某种警告系统来防止这种行为。现在,我们的代码进行了大量的并发检查以确保数据完整性,但仍然存在数据损坏问题。

我的解决方案,在发现一般答案是“不可能”后,依靠AJAX发出“ping”并测量之间的时间。因此,我们有一个通用规则:我们以一定的间隔“ping”,如果当前ping中最后一次ping的增量 less 比ping持续时间更长,我们知道我们有多个活动的浏览器会话在单个服务器会话上。

那么,Pf是ping频率; Pc是当前的ping;并且Pl是最后一次ping,然后我们在Pf > (Pc - Pl)时出错。

           p1    p2    p3    p4
TAB1 0-----|-----|-----|-----|---...
                 :     :     :
                 :  p1 :  p2 :  p3    p4
TAB2          0-----|-----|-----|-----|---...
     ^     ^     ^  ^  ^  ^  ^  ^
                  Deltas
----+---+------------
TAB | P |   Delta (Pc - Pl)
----+---+------------                 
 1  | 1 |   5
 1  | 2 |   5
 2  | 1 |   2.5 -Error
 1  | 3 |   2.5 -Error
 2  | 2 |   2.5 -Error

现在,如果存在网络拥塞或其他因素,那么增量将更大而不是频率,排除误报。

如果两个标签在完全相同的momemnt处打开,我们确实遇到了问题。但是,由于ping频率只是发出请求的频率,而不是保证的经过时间,我们可以假设很快两个浏览器会话将开始滑动不同步。

在示例中,我将ping频率设置为每5秒。如果有100个并发用户,那么我们正在查看ping Servlet / HttpModule的~20个请求/秒。为了最大限度地减少不必要的网络流量,我认为ping频率会随着时间的推移而衰减,直到达到最大20 pings /秒。对于100个并发用户,这将达到约5个请求/秒。然而,这是一种权衡,因为它会导致检测延迟。但是,一旦发生检测,频率将重置为5次/秒,直至解决。 (这些数字仅作为示例;它们会根据环境而变化)

为了最小化并发性和可伸缩性问题,会话的最后一个ping时间戳应保留在会话本身中。这将允许任何分布式会话技术在JVM或应用程序域之间维护会话的可用性,而我们的ping服务不需要知道它。

我正在努力确定这是否是一个合理的方法,如果我是一个受伤的世界。任何有关该问题的经验都会有所帮助。

编辑:我知道这听起来像是一个创可贴,但这是一个权宜之计,直到我们能够删除有问题的图书馆。

7 个答案:

答案 0 :(得分:2)

多年前我在一个窗口Web应用程序上工作(在约会“Web 2.0”之前)。我们只是启动了一个没有任何工具栏的新窗口(没有后退按钮等)并禁用了右键单击。我们注意创建一个非常有用的会话导航系统。这足以防止几乎所有意外的重复浏览。这是一个内联网应用程序;显然我从不建议在一般网站上做这样的事情。

就个人而言,我不喜欢ping探测器的声音。我只是确保不会发生任何数据损坏。多个浏览器会话不是一个有效的借口...虽然我理解它可能有问题。但是如果你想在完美工作的代码之上添加一个ping检测器,那么它可以作为一个有用的提醒用户。

您可以在每个链接的末尾添加唯一标记。如果多次使用唯一令牌(例如,打开新窗口,加书签,返回,转发),则可以拒绝该请求。通过适当的跟踪,您可以确保在不采用有效路径的情况下永远无法从一个页面到另一个页面。这种方法比ping更可靠(因为它由服务器控制),但可能导致非常讨厌的用户体验。

缺点是:修复您的应用程序以不破坏任何数据。我知道这可能不是一件微不足道的事情,我并不是要贬低它。实施ping等可能有助于使问题消失,但我向你保证,如果出现问题,它最终会出错。 : - )

答案 1 :(得分:2)

用户使用什么浏览器?
当IE8问世时,我们解决了数据损坏问题,并提供了NoMerge选项。

答案 2 :(得分:2)

您可以使用在客户端上创建的javascript和cookie以及浏览器/ DOM窗口名称必须唯一的事实来实现此目的。非常容易使用而无需更改您的网站。

1)第一次加载页面时检查您的会话cookie是否存在,如果不存在,则创建一个会话cookie(不设置过期日期),并使用唯一的名称和值(某些一种代码)。使用此cookie值设置浏览器/ dom窗口名称(不是标题)。

2)在后续请求中,您需要检查DOM窗口名称是否与cookie值相同 - 如果没有重定向到错误页面。

3)请记住删除页面上的cookie,以便关闭窗口会删除cookie。

这是有效的,因为如果您尝试打开一个重复的窗口,则复制窗口将不具有与cookie值相同的窗口DOM名称 - 您可以响应该事实。

代码示例

function CheckMultipleSession() {
var existingCookieValue = getCookie("MySessionCookie");
if (existingCookieValue == null) { //first request so create cookie
   currentCookieValue = guid();
   setCookie("SessionGUID", currentCookieValue); 
   window.name = currentCookieValue; // setting DOM window name (this is key)
}
else {
if (existingCookieValue != window.name)
   top.location = "MultipleSessionsError.htm";                                       
}
}

答案 3 :(得分:1)

我主要担心的是,当网络延迟时,这是否会受到影响。也就是说,任何麻烦都可能来自通常首先使用ping的问题。

答案 4 :(得分:1)

如果您确实处于绑定状态并且无法修复应用程序以合理地处理共享同一会话的多个浏览器实例,那么是的,这是一种合理的方法。

对于它的价值,我使用完全相同的概念来强制执行并发使用许可限制 - 因此它将检测共享相同“密钥”的多个用户,在您的情况下是会话。

我只会略微修改您的方法,并且ping消息包含客户端的日期/时间 - 这样您就可以避免在计算中处理网络延迟。

答案 5 :(得分:1)

当天为时已晚。但您可能希望考虑在服务器上生成随机字符串并以隐藏形式将其发送到前端的选项。在用户的会话对象中维护会话的最后一个随机密钥。每次用户向服务器发出请求时,都会发回此随机密钥。使用存储在会话中的随机密钥检查浏览器中的随机密钥。如果它们不匹配,那么您可以告诉用户他们应该使用其他窗口。不是非常用户友好,但会工作。

答案 6 :(得分:0)

您可能会或可能无法使用的一个非常简单的解决方案是ajax应用程序具有单个页面(即,单个URL,例如home.whatever)。如果他们第二次请求同一页面并且已经存在有效会话,那么您知道他们打开了新选项卡或新窗口。但请注意,您无法将其与刷新区分开来。

你的解决方案太复杂了。