20

Few weeks ago we had one of our customers contacting us saying that sometimes when he creates an activity it gets created under someone else's name!

We did some troubleshooting and couldn't find anything. We asked the user to contact us the next time he was experiencing these issues. He did contact us and we were able to do a gotomeeting with him and see the issue with our own eyes.

It was not only the activities, he was recognized as someone else in the application. He had access to everything that other person should had access to. That was when we realized we are having a session mixed up issue.

A little bit about our code:
Like any other application we have a simple login page that user enter email and password and we authenticate them against our database and if they are valid we call FormsAuthentication.SetAuthCookie() to save current user id in the cookie and we let him in.

BL.User currentUser = BL.User.Authenticate(txtUsername.Text, txtPassword.Text);

if (currentUser != null)
{
    this.Session["NumberOfLoginTried"] = "0";
    FormsAuthentication.SetAuthCookie(currentUser.UserID.ToString(), chRememberMe.Checked);
    Response.Redirect(FormsAuthentication.GetRedirectUrl(currentUser.UserID.ToString(), false));
}

We also use the following piece of code to get logged-in user id (current user) in our application.

public static int GetCurrentUserID()
{
    int userID = -1;
    int.TryParse(HttpContext.Current.User.Identity.Name, out userID);
    return userID;
}

And yes we did our homework and googled around and have seen the following two links:

http://lionsden.co.il/codeden/?p=446
ASP.NET Session Mix-up using StateServer (SCARY!)

We have disabled kernel-mode caching and user-mode caching for .aspx and .ascx files and this is still happening.

P.S- The app is running on Windows 2008 R2 with IIS 7.5. And we are NOT using cookieless session.

Community
  • 1
  • 1
Houda
  • 805
  • 3
  • 11
  • 17
  • Is your user checking the "Remember Me" box? And is there any pattern to what wrong user your user is changing to (e.g., is it always the same user? Is it another user at the same location (big hint if so), is it another logged in user, etc.)? – KP Taylor Apr 07 '11 at 00:19
  • @houda, where did you store the session ? (sql, mem ?) If its on sql, do you run the autoclear script every minute ?. Also, why the error is on that functions ? maybe there is some other error that you have miss. Do you use WebGarden ? (many asp.net process ?) – Aristos Apr 07 '11 at 00:48
  • 2
    @houda there is also the possibility that the pages stored on a proxy , and you users see the previous user proxy stored pages! Do you have set "no-cache" ? and no proxy allowed ? Are the pages https ? Is your client on an office that connect to the internet from a proxy-router ? – Aristos Apr 07 '11 at 01:04
  • @houda, I'm confused by your GetCurrentUserID routine -- why do you expect HttpContext.Current.User.Identity.Name to parse to an int? In addition, if TryParse fails, it will set userID to 0, not leave it set at -1. – Andrew Apr 07 '11 at 01:13
  • @Ken It is all random I couldn't find any pattern. – Houda Apr 07 '11 at 16:45
  • @Aristos Sessions are being stored in the memory. No WebGarden. The issue is sessions being crossed I monitored sessionIDs and saw this first hand. I am going to set no-catch and no proxy allowed (I don't know exactly how to do that, can you put me in the right direction please?). The pages are all https. YES SOME OF OUR CLIENTS ARE IN THE SAME OFFICE AND THEY MIGHT HAVE PROXY ROUTER. – Houda Apr 07 '11 at 16:48
  • @Houda Have you solved your problem? – Jacob Phan Jan 19 '16 at 10:39
  • @Hauda, can you solved? I have same problem. – Cagdas Feb 28 '17 at 08:59

7 Answers7

14

We have just had a very similar problem, which occured at random, seemingly un-reproducibly.

The problem turned out to be ASP.NETs Page caching mechanism - in our case the <%@ OutputCache tag in particular.

There was a line we had used <%@ OutputCache NoStore="true" Duration="1" %> that basically meant if two users accessed the same page within 1 second of each other they would see the same page (including the logged in username of the other user). So if they refreshed said page, they got the correct information.

In our case, changing said line to <%@ OutputCache NoStore="true" Duration="1" VaryByParam="*" %>, disabling kernel caching in IIS as in this link (http://lionsden.co.il/codeden/?p=446)

and adding the following lines to the Page_Load event of the page in question:

Response.CacheControl = "private";
Response.ExpiresAbsolute = DateTime.Now.AddDays(-1d);
Response.Cache.SetCacheability(HttpCacheability.NoCache);

Seems to have solved the problem for us. Hopefully this helps someone else with a similar issue.

Joebone
  • 550
  • 3
  • 16
4

We had the same problem and it was caused by the <clientCache/> setting in IIS, which by default fails to add the Cache-Control: private HTTP header. The lack of this header meant that our Forms Authentication cookies were being cached by downstream proxy servers! So when our site got busy, all of a sudden a load of users would suddenly get logged in as the wrong user! Nightmare.

Ben Collins
  • 166
  • 2
  • 6
3

We had the same problem at the company I work at. We also realized that it was caused by output caching, which resulted in sending someone else's SessionId to the wrong person.

We have now added the following <caching> element to our web.config.

<configuration>
  [...]
  <system.webServer>
    [...]
    <caching enabled="false" enableKernelCache="false">
    </caching>
  </system.webServer>
  [..]
</configuration>

We can't guarantee this will solve it, because the problem is almost impossible to reproduce, but based on our research, this should solve it.

Strangely, the link to a Microsoft article describing this problem that can be found on the internet gives some general page as if the page has been deleted.

But there is this Microsoft article that seems to describe the same issue voor IIS 6:

An ASP.NET page is stored in the HTTP.sys kernel cache in IIS 6.0 when the ASP.NET page generates an HTTP header that contains a Set-Cookie response

Which describes the symptom as:

Consider the following scenario. A Microsoft ASP.NET page contains the <%@ OutputCache %> directive. Additionally, the ASP.NET page generates an HTTP header that contains a Set-Cookie response. In this scenario, the ASP.NET page is stored in the HTTP protocol stack (HTTP.sys) kernel cache in Microsoft Internet Information Services (IIS) 6.0. Therefore, multiple users who access the same page may receive identical cookies.

Update

I found this really good article at Microsoft Premier Developer blog that explains a lot:

ASP.Net Session Swapping – Why it happens and what can be done about it?

Sander_P
  • 1,826
  • 1
  • 11
  • 33
3

if removing the <%@ OutputCache NoStore="true" Duration="1" VaryByParam="*" at all (in all ascx files being in the line from Master to aspx too !!!) prevented from cross-sessions. having only one ascx with outputcache directive loaded, cross-sessions occured.

It did not matter in my case if using sessionstat InProc ore StateServer, if having cookieless or cookie sessions.

Hans
  • 31
  • 1
2

Because you all disabled kernel-mode caching, I like to point out some other thinks.

1) To correctly use the HttpContext.Current.User.Identity.Name, you first need to verify that your user is logedin by using the User.Identity.IsAuthenticated

2) in this point Session.Add("CurrentUser", currentUser); what are you actual try to save ?

Now I think that is the problem is on cache. The pages are stored somewhere in between your users and the one mix up with the other. Some of the headers that you can use to your page to avoid the cache on the middle proxy computers.

Response.Cache.SetExpires(DateTime.UtcNow.AddYears(-2));
Response.Cache.SetNoStore();
Response.Cache.SetValidUntilExpires(false);
Response.Cache.SetCacheability(HttpCacheability.NoCache);                
Response.ExpiresAbsolute = DateTime.Now.Subtract(new TimeSpan(1, 0, 0, 0));
Response.Expires = 0;
Response.CacheControl = "no-cache";
Response.AppendHeader("Pragma", "no-cache");

Also I say that if your pages have data that you do not wish to share among your user you need to use Secure HTTPS pages, and set your cookies to be available only on secure pages by adding <httpCookies httpOnlyCookies="true" requireSSL="true" /> on web.config

Also, check if you save your session on SQL server that you scheduled run the clean up routing every 1 minute.

To been able to find some more information I suggest to store some hidden text on the pages, eg the date-time of the rendered, maybe a the last 4 digit of the userID, and what else you may thing that can help you see if the page come from a cache or not.

Aristos
  • 63,580
  • 14
  • 112
  • 146
  • Session.Add("CurrentUser", currentUser) is an old line of code that is not being used anymore. – Houda Apr 07 '11 at 17:16
  • @Houda for the not allowed to proxy set this response that I have place on the answer here, maybe you can find more or less on the Internet, but I think that the problem is the proxy on the office, just disable the cache on the page by this headers and I think you going to solve it. – Aristos Apr 07 '11 at 21:42
  • @Houda also I say that is better handled if you move your session on SQL server. At least in my case I have some problems when I use the InProc. – Aristos Apr 07 '11 at 21:45
  • I added the headers to all the pages. The problem is still happening but not as much as before. Any other suggestion? – Houda Apr 25 '11 at 17:25
  • I added the headers to all the pages. The problem is still happening but not as much as before. The irony is because we use iFrame a lot in our project and as you know iFrames get cached aggressively; we had added a random string to the end of all URLs when they are being pulled by client. Any other suggestion? – Houda Apr 25 '11 at 17:33
2

Since this seems to fall into the extremely arcane problem territory, maybe it's time for a leap.

You could stop using the ASP.NET session to store your identifiers altogether.

You have a bunch of options of where you could stick this information instead. You could choose to encrypt it into the Forms Authentication ticket's UserData property (I've done this before in production, it works great for storing a key(s), csv of roles, or even small json objects). Past the forms auth ticket, you could write the information directly as your own cookie. You could also bypass cookies altogether.

If you choose to bypass the cookies, you're basically entering into similar territory of the cookieless ASP.NET sessions. You have a couple of options, you could make the user identifier be apart of every single url as a query parameter. Another option would be to create a HttpModule that would add a hidden form input into every page response that contains the logged in user's identifier.

If you go down the cookieless path absolutely make sure it's not possible to use your site as HTTP and every single request is HTTPS. Even more especially if you use the query parameter method.

Chris Marisic
  • 30,638
  • 21
  • 158
  • 255
  • What is really confusing for me is the fact that the user information and sessionid are both being stored in cookies not in the state. Basically when I call HttpContext.Current.User.Identity.Name I am accessing a cookie. Are these cookies being cached in a proxy?! – Houda Apr 27 '11 at 21:50
  • It's possible they're being cached by proxy, that would be something you should be able to test readily enough. That might make my notion of adding the identifiers directly to the form as a bypass. It might not cache that, of course it could also cache this. Trying to fight broken systems is always a losing battle. – Chris Marisic Apr 29 '11 at 14:08
0

If you checked that output caching is not the problem

There is already on answer from me here, but as it turned out my other solution (disabling the output cache) did not really solve our problem for us.

Since in the question it is stated that caching is turned off, the only other possible (AFAIK) bug that can produce this is what turned out to be the real culprit in our case: we use a private variable in a ActionFilterAttribute.

And because these are cached, storing private/personal data from a user in this way can also lead to session mix-up!

This answer describes what our problem was and how to fix it:

https://stackoverflow.com/a/8937793/1864395

Also, I think it's good to mention that we were able to reproduce the problem by running Apache JMeter with a scenario for several users at the same time. It's a really nice tool (although not really user friendly/intuitive) used for (among other things) stress-testing. It's probably the only way to diagnose session mix-ups!

Sander_P
  • 1,826
  • 1
  • 11
  • 33