Preventing multiple browser sessions on the same server session
I'm sure we've all worked on, or are aware of web applications (especially in the enterprise) that have tightly bound themselves to the server session. In these cases, it's possible that the session will become corrupted if more than one browser session is open and using the same server session cookie. We've examined all of the options and found the best way to move forward would be to discourage the use of multiple browser sessions that share a server session cookie.
This is only really a problem when a user executes New Window - Ctrl+N
in IE or the equivalent of "duplicate tab" in other browsers. Essentially we end up with two active browser sessions sharing the same cookies.
So, to discourage this (as it will likely be inadvertent) I've set out to put some kind of warning system in place to prevent this behavior. Now, our code does plenty of concurrency checking to ensure data integrity, but there can still be issues with data corruption.
My solution, after finding that the general answer is "it's impossible" was to rely on AJAX to send out "pings" and measure the time between. So, we have a general rule: we "ping" at a certain interval and if the delta between the last ping in the current ping is less than the ping duration, we know we have multiple active browser sessions on a single server session.
So, where Pf
is ping frequency; Pc
is current ping; and Pl
is last ping, then we have an error when 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
Now, if there is network congestion or other factors, then the delta will be greater than the frequency, ruling out false-positives.
We do have a problem if two tabs are open at the exact same momemnt. But, since the ping frequency is just the frequency at which the requests are made, and not a guaranteed elapsed time, we can assume that soon the two browser sessions will begin sliding out of sync.
In the example, I have the ping frequency set to every 5 seconds. If there are 100 simultaneous users then we're lookiing at ~20 requests/second for the ping Servlet/HttpModule. To minimize unnecessary network traffic开发者_运维技巧 I was thinking that the ping frequency would decay as time went on until a maximum of 20 pings/second was reached. This would amount to ~5 requests/second with 100 concurrent users. This is a trade-off, though, as it will cause a delay in detection. However, once detection occurs, the frequency resets to 5 pings/second until resolved. (These numbers are just as an example; they would vary a based on the environment)
To minimize concurrency and scalability issues, the last ping timestamp for the session should be kept in the session itself. This will allow any distributed session technology to maintain the availability of the session across JVMs or app domains without our ping service needing to be aware of it.
I'm trying to determine whether or not this is a sound approach of if I'm in for a world of hurt. Any experience with the issue would be helpful.
EDIT: I know this sounds like a band-aid, but this is meant to be a stopgap measure until we can rip out the offending library.
I worked on a single window web application many years ago (pre-dating "Web 2.0"). We simply launched a new window without any toolbars (no back button, etc) and disabled right-clicking. We took care to create a very usable in-session navigation system. This was enough to prevent almost all accidental duplicate browsing. This was an intranet application; obviously I'd never recommend doing anything like this on a general website.
Personally, I don't like the sound of the ping detector. I would just make sure that no data corruption can ever possibly occur. Multiple browser sessions is not a valid excuse for that... although I understand how it can be problematic. But if you want to add a ping detector on top of perfectly working code, then it might serve as a helpful reminder to the user.
You could add a unique token to the end of every link. If the unique token is used more than once (e.g., opening a new window, bookmarking, back, forward), then the request could be denied. With proper tracking, you could ensure that it's never possible to get from one page to another without taking a valid path. This approach is more reliable than the ping (as it is controlled by the server), but could result in a very annoying user experience.
The short of it is: fix your application to not corrupt any data. I know that may not be a trivial thing, and I don't mean to make light of it. Implementing pings and such may help make the problem disappear, but I guarantee you that if something can go wrong, it eventually will. :-)
What browser do the users use?
We solved a data corruption solution when IE8 came out, and provided the NoMerge
option.
You can achieve this using javascript and cookies created on the client in combination with the fact that a browser/DOM window name must be unique. Very easy to use without changing your site.
1) The first time your page is loaded check if your session cookie exists and if not then create a session cookie (don't set the expiry date) with a unique name and value (some kind of code). Set the browser/dom window name (NOT the title) with this cookie value.
2) On subsequent requests you need to check that the DOM window name is the same as the cookie value - if not redirect to error page.
3) Remember to delete the cookie on the page's unload so that closing the window removes the cookie.
This works because if you try and open a duplicate window, the duplicate window will not have the same window DOM name as the cookie value - and you can respond to the fact.
Code example
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";
}
}
My major concern would be whether this gets compromised when there's network latency. That is, any trouble would probably come from issues for which ping is generally used for in the first place.
If you really are in a bind and cannot fix the application to sanely handle multiple browser instances sharing the same session, then yes, this is a sound approach.
For what it is worth, I have used the exact same concept to enforce concurrent usage license constraints - so it WILL detect multiple users sharing the same "key", which in your case is the session.
I would modify your approach only slightly, and have the ping message contain the date/time of the client - so that you can avoid dealing with network latency at all in your calculations.
It is too late in the day. But you may wish to consider the option of generating a random string at the server and sending this to the frontend in a hidden form. Maintain the last random key for the session in the session object of the user. Everytime the user makes a request to the server send this random key back. Check the random key from the browser with the one stored in the session. If they do not match then you can tell the user that they should use the other window. Not very user friendly, but would work.
A very simple solution that you may or may not be able to use is have a single page (ie, a single URL such as home.whatever) for the ajax application. If they request that same page a second time and there is already a valid session, then you know they opened a new tab or a new window. Note that you wouldn't be able to distinguish this from a refresh, however.
Your solution is way too complicated.
精彩评论