views:

84

answers:

6

I've recently been developing a website using asp.net webforms that uses in proc sessions and I noticed that session ids are shared amongst browser tabs. So I was wondering what you would do for the following situations:

Problem: Multiple logins with different users in the one browser problem

  1. User opens browser tab 1, logins with "user1" - store in session
  2. User opens browser tab 2, logins with "user2" - store in session
  3. At this stage session information is now pointing to "user2" because of how session id is shared amongst browser tabs
  4. User tries an action on tab 1 and suddenly they have "user2" information

How do you alert the user in tab 1 that the user has changed or how do force tab1 user to logout?

My initial thought was to keep a list of active users with session id via database or application object, but the problem I face is that in tab 1 what am I going to compare the list against, when I do a request the HttpContext.Current.User would be updated with "user2" how do I know browser tab 1 was initially for "user1"

Appreciate anyone letting me know of any alternatives or best practices for the above problem

Regards DotnetShadow

+4  A: 

Why don't you warn when user2 logs in instead? With a message like "You are already logged in as user1, are you sure you want to login again as another user?"

klausbyskov
That seems reasonable, I guess nothing much can be done in tab 1
DotnetShadow
+1  A: 

That's just how it is. You can't do much about it. Users are now accustomed to this behavior as it is consistent among famous internet sites like gmail, etc... so it shouldn't be much of a problem to them.

Darin Dimitrov
My only concern is if your on a page where you have to submit data. Initially before submission the page was rendered as user1, if after logging in tab2 and switching back to tab1 the user presses submit now it will submit with user2 in mind wouldn't it?
DotnetShadow
+1  A: 

All tabs in a browser belong to the same instance, so all tabs share cookies and sessions, there isnt much you can do about it. If you want to implement this badly the only solution that comes to mind is carrying a unique session id with each URL. Based on that unique id you can link a specific user. You will need customize the session logic and would have to make sure all links in your website carry this unique id. It could be done with alot of effort but the real question is , is it worth doing?

Sabeen Malik
This is built into (and not badly) many web frameworks already. It's usually called cookie-less authentication, or URL authentication, or something like that.
bzlm
@bzlm: this is not the same thing as cookieless sessions.
Eamon Nerbonne
@Eamon How so? "Carrying a unique session id with each URL" sounds exactly like the typical implementation of cookie-less sessions.
bzlm
See my answer; but basically, you have both a cookie and an id in the URL. Using only the URL to store the ID is less secure and less human-friendly due to longer URLs; particularly since you probably want the session ID to be *first* in the path. It's an eminently practical solution nonetheless, but there are practical differences.
Eamon Nerbonne
@Eamon The phrase "Based on that unique id you can link a specific user" in this answer sounds to me like the answer does describe cookie-less sessions. Otherwise, the session cookie could already be used to "link a specific user". Only @Sabeen knows!
bzlm
Ah, I mean *in general* - yeah, It's also not clear to me whether Sabeen means session-specific user ids or more global session ids.
Eamon Nerbonne
to be clear i actually did mean cookie-less sessions, because we cant rely on cookies once again. Another solution could be to have a folder path specific cookies. Where once someone authenticates you send them to site.com/user/whatever , that maybe easier to implement than taking a unique id across the whole site.
Sabeen Malik
@Sabeen Malik I like your idea of having the folder path, I'm using asp.net webforms would you have an idea how I would go about making sure all links carry the /user/ path. Is there an user method than <asp:hyperlink navigaturl=<% GetPath() %>/page2.aspx ....
DotnetShadow
@DotnetShadow ... I am glad you found my comment useful however i am not a .NET guy really so cant really help you there, i think it would be better to post a new question on SO for that.
Sabeen Malik
+1  A: 

What I do to avoid this problem is redirect to append a short, random in-url login-identifier.

Then, rather than use session directly, I store a strongly typed object in the session vars under the random in-url code, and use that object for session storage. If you want to keep it simple, you could use a Dictionary. In addition to the normal session timeout, you should keep track of the last usage within each login-id and manually time-out a session if it's too old to avoid new users from keeping old logins alive.

Essentially then, each ASP.NET session corresponds to any number of login sessions.

This has the following advantages:

  • You can log in as multiple users simultaneously. That's handy to be able to do for many sites.
  • In public terminals, it helps avoid accidental session hijacking. When a user leaves a public terminal, closes the webapp tab but not the browser (which is quite common) and another person then approaches that terminal and opens a new window or tab to your site, this new user sees no trace of the previously logged in user. Of course, users should log out, and anyone can inspect the history, but there's no reason to invite abuse.
  • CSRF attacks against your site are a little bit harder since a url without the random login-id is meaningless.
  • The implemenation is quite simple if you use a hashtable - after all, any sessionstate-consumer already is written to store and retrieve data from a hashtable, you just need to change the hashtable it's using and should ideally include a custom timeout.

The obvious downside is that you need to include the random code in the url; and that you need a bit of extra implementation. You might hide the extra code using an iframe and/or javascript+XHR based site, but doing so is a much more invasive change to a site. Finally, note that cookieless sessions are not the same; though they're simpler to turn on, they involve a much longer less human-friendly url token, and by lacking the normal cookie session token, also are less secure vs. session hijacking (since suddenly any other program or even machine that discovers the session ID can pretend to be that user).

Eamon Nerbonne
Your solution seems good but how do you keep the random in-url login-identifier on every link on your website? Like if I got 10 links on page1, then 20 links on page 2 do dynamically append links via page_load, i.e. Read the querystring then add them to all links, what happens if people change the identifier do you force a relogin? Would you use a httpmodule to rewrite links or something?
DotnetShadow
You can use relative urls, for instance. Alternatively, simply expose the full path to the current session as a helper variable somewhere and use that to compose URLs. After all, you need to do similar things to deal with Web application roots too - right?
Eamon Nerbonne
If you're using ASP.NET MVC or Routing, for instance, you could just include the session id as the first component in all your routes directly.
Eamon Nerbonne
@Eamon Nerbonne unfortunately I'm using asp.net webforms, I was thinking of using an asp.net httpmodule that would loop through my hyperlinks and modify them not sure if that's a viable solution
DotnetShadow
That's certainly viable, but it may be overkill - can't you control the link prefix at the moment the link is created, or simply use relative links if the links are static?
Eamon Nerbonne
Yeah I was thinking more of the static links and making sure they get the appended information was thinking of doing url rewrites with maybe paths /6243dsg7sga/page1.aspx but not sure
DotnetShadow
I use just 4-to-5 letters, after all, how many logins do you need in one browser? As for the link you mention; that link is unhandy anyhow since it will break if you ever mount the web-application under a different IIS application. So, you kind-of need to use relative links for most such static links anyhow; and for the rest you'll do something like `<a href="<%=VirtualPathUtility.AppendTrailingSlash( context.Request.ApplicationPath)+TOKEN+"/" %>my/app/relative/absolute/path">`
Eamon Nerbonne
Of course `VirtualPathUtility.AppendTrailingSlash( context.Request.ApplicationPath) + TOKEN +"/"` is screaming for a helper method, such as an Extension method of HttpContext.
Eamon Nerbonne
Sounds good, I'm just a little confused about the my/app/relative/absolute/path is that trying to say followed by any one of those?So if I had a path as http://localhost/foo/secure/page1.aspxIt should translate to http://localhost/foo/TOKEN/secure/page1.aspx?
DotnetShadow
Just to also confirm if there is any link on the website that doesn't carry on the token then there will be no way to get the information from the session as the token can't be retrieved correct?app/TOKEN/page1.aspx navigate to app/page2.aspx now no token so if I click on any other link from this point onwards I don't know what the token is anymore
DotnetShadow
The only way to get the token is to extract it from the browser or the server. It can be extracted from the browser simply by inspecting the history; but third party sites can't do that and human beings sharing the same OS-login presumably trust each other (or are in fact the same human with multiple website accounts). It can be extracted from the server if you give them the token - but why would you do that? Also, there will be several tokens, possibly, meaning that it's a very unlikely bug to accidentally reveal "the" token - except of course the *current* token, which is of course OK.
Eamon Nerbonne
If you navigate from http://localhost/iisApp/TOKEN/page1.aspx to http://localhost/iisApp/page2.aspx then on the browser side, the user can still click back and retrieve the TOKEN, and on the server side, you may be able to extract it from the referer. If you then go to http://localhost/iisApp/page3.aspx, the user can still click back, but the server is really out of luck: it can use some heuristics, of course (if there's only one token, say, or if it store the entire history and the back-link chain is unique, or some such thing). But not trivially, anyhow, and *you* wrote the server...
Eamon Nerbonne
+2  A: 

Some have suggested adding uniquifiers into the URL, and tracking based on those.

If you're going to do this, you may as well just let ASP.Net do this for you by turning on cookieless sessions - it then uses the URL to contain the session ID.

Damien_The_Unbeliever
"Some" being me - cookieless sessions are more susceptible to session hijacking and have much longer, less user-readable URLs.
Eamon Nerbonne
@Eamon - well, you and Sabeen. And I did link to an article that describes pros and cons.
Damien_The_Unbeliever
Indeed you did, and cookieless sessions are certainly a *simple* alternative, which is in itself a virtue - +1. However, I'm not too thrilled with the pure cookieless approach myself, for the above reasons.
Eamon Nerbonne
+1  A: 

How about storing the data in viewstate? That would be unique to every window.

Yeodave
Why is this downvoted? It's actually more secure than using cookieless sessions...
Eamon Nerbonne