Asp.net会话交叉/混合

时间:2011-04-07 00:01:29

标签: asp.net iis-7.5 session-cookies

几周前,我们有一位客户联系我们说,有时当他创建活动时,它会以别人的名义创建!

我们做了一些故障排除,找不到任何东西。我们要求用户在下次遇到这些问题时与我们联系。他确实与我们联系,我们能够与他进行一次讨论,并亲眼看到问题。

不仅是活动,他在应用程序中被认可为其他人。他可以访问其他人应该访问的所有内容。就在那时我们意识到我们正在讨论混合问题。

关于我们的代码: 像任何其他应用程序一样,我们有一个简单的登录页面,用户输入电子邮件和密码,我们根据数据库对它们进行身份验证,如果它们有效,我们调用FormsAuthentication.SetAuthCookie()将当前用户ID保存在cookie中,我们让他进入。 / p>

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));
}

我们还使用以下代码在我们的应用程序中获取登录用户ID(当前用户)。

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

是的,我们做了我们的家庭作业并用Google搜索,并看到了以下两个链接:

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

我们已禁用.aspx和.ascx文件的内核模式缓存和用户模式缓存,但这仍然存在。

P.S-该应用程序在带有IIS 7.5的Windows 2008 R2上运行。我们使用无Cookie会话。

7 个答案:

答案 0 :(得分:13)

我们遇到了一个非常类似的问题,这个问题随机发生,似乎无法重现。

问题原来是ASP.NETs页面缓存机制 - 在我们的例子中特别是<%@ OutputCache标签。

我们使用了一条线 <%@ OutputCache NoStore="true" Duration="1" %>这基本上意味着如果两个用户在1秒内访问同一页面,他们将看到相同的页面(包括其他用户的登录用户名)。因此,如果他们刷新了所述页面,他们就会得到正确的信息。

在我们的案例中,将所述行更改为 <%@ OutputCache NoStore="true" Duration="1" VaryByParam="*" %>,在IIS中禁用内核缓存,如此链接(http://lionsden.co.il/codeden/?p=446

并将以下行添加到相关网页的Page_Load事件中:

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

似乎已经为我们解决了问题。希望这可以帮助其他有类似问题的人。

答案 1 :(得分:4)

我们遇到了同样的问题,它是由IIS中的<clientCache/>设置引起的,默认情况下无法添加Cache-Control: private HTTP标头。缺少此标头意味着我们的表单身份验证cookie正由下游代理服务器缓存!因此,当我们的网站忙碌时,突然有大量用户突然以错误的用户身份登录!梦魇。

答案 2 :(得分:3)

如果完全删除<%@ OutputCache NoStore="true" Duration="1" VaryByParam="*"(在从Master到aspx的行中的所有ascx文件中)也阻止了跨会话。只加载了一个带有outputcache指令的ascx,发生了跨会话。

在我的情况下,如果使用sessionstat InProc ore StateServer,如果有cookieless或cookie会话则无关紧要。

答案 3 :(得分:3)

我们工作的公司遇到了同样的问题。我们还意识到它是由输出缓存引起的,导致将其他人的SessionId发送给错误的人。

我们现在已将以下<caching>元素添加到我们的web.config中。

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

我们无法保证这会解决它,因为这个问题几乎不可能重现,但根据我们的研究,这应该可以解决它。

奇怪的是,可以在互联网上找到描述此问题的Microsoft文章的链接提供了一些常规页面,就像页面已被删除一样。

但是这篇微软文章似乎描述了与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

其中症状描述为:

  

请考虑以下情形。 Microsoft ASP.NET页面包含&lt;%@ OutputCache%&gt;指示。此外,ASP.NET页面生成包含Set-Cookie响应的HTTP标头。在此方案中,ASP.NET页面存储在Microsoft Internet信息服务(IIS)6.0中的HTTP协议堆栈(HTTP.sys)内核缓存中。因此,访问同一页面的多个用户可能会收到相同的Cookie。

<强>更新

我在Microsoft Premier Developer博客上发现这篇非常好的文章解释了很多:

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

答案 4 :(得分:2)

因为你们都禁用了内核模式缓存,所以我想指出其他一些想法。

1)要正确使用HttpContext.Current.User.Identity.Name,首先需要使用User.Identity.IsAuthenticated

验证您的用户是否为logedin

2)在这一点上Session.Add("CurrentUser", currentUser);你真正试图保存什么?

现在我认为问题在于缓存。页面存储在用户之间的某个位置,而另一个用户则混合在一起。您可以使用一些标题来避免中间代理计算机上的缓存。

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");

另请注意,如果您的网页包含您不希望在用户之间共享的数据,则需要使用安全HTTPS页面,并通过在网络上添加<httpCookies httpOnlyCookies="true" requireSSL="true" />将Cookie设置为仅在安全页面上可用的.config

另外,检查您是否在每1分钟运行清理路由的SQL服务器上保存会话。

为了能够找到更多信息,我建议在页面上存储一些隐藏文本,例如渲染的日期时间,也许是用户ID的最后4位数,以及你可能有什么其他可以帮助的东西你看看页面是否来自缓存。

答案 5 :(得分:2)

由于这似乎属于极其神秘的问题领域,也许是时候实现跨越式发展了。

您可以停止使用ASP.NET会话来完全存储您的标识符。

您有很多选项可以在哪里添加此信息。您可以选择将其加密到Forms Authentication票证的UserData属性中(我在生产之前已经完成了这项工作,它非常适合存储密钥,csv角色,甚至小json对象)。通过表单身份验证票证,您可以直接将信息写为自己的cookie。你也可以完全绕过cookie。

如果您选择绕过cookie,您基本上会进入无cookie的ASP.NET会话的类似区域。您有几个选项,您可以将用户标识符作为查询参数分隔每个URL。另一种选择是创建一个HttpModule,它将隐藏的表单输入添加到包含登录用户标识符的每个页面响应中。

如果您沿着无cookie路径前进,请确保无法将您的站点用作HTTP,并且每个请求都是HTTPS。更特别是如果您使用查询参数方法。

答案 6 :(得分:0)

如果您检查输出缓存不是问题

我已经在这里回答了问题,但事实证明我的另一个解决方案(禁用输出缓存)并没有真正解决我们的问题。

因为在问题中声明缓存是关闭的,所以唯一可能产生这种情况的其他可能的(AFAIK)错误就是我们案例中的真正罪魁祸首:我们在{{中使用私有变量1}}。

因为这些是缓存的,以这种方式存储来自用户的私人/个人数据也会导致会话混淆!

这个答案描述了我们的问题以及如何解决它:

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

另外,我认为我们能够通过同时为多个用户运行Apache JMeter来重现问题。这是一个非常好的工具(虽然不是真正用户友好/直观)用于(除其他外)压力测试。 这可能是诊断会话混淆的唯一方法!