6

编码:

Session["foo"] = "bar";  
Response.Redirect("foo.aspx");

问题:

当 foo.aspx 从会话中读取“foo”时,它不存在。会话在那里,但“foo”没有任何价值。

我在我们的生产环境中间歇性地观察到这一点。但我在这里并不是要问一个关于 Response.Redirect() 的问题

说明:

Bertrand Le Roy解释说(粗体字是我的):

现在,重定向所做的是向客户端发送一个特殊的标头,以便它向服务器请求与它等待的页面不同的页面。服务端,发送这个header后,Redirect结束响应。 这是一件非常暴力的事情。 Response.End 实际上会在页面使用 ThreadAbortException 时停止执行。这里真正发生的是 会话令牌在战斗中丢失。

我的收获是 Response.Redirect() 可以通过结束线程来处理。如果它们发生得太接近那种严厉,那可能会威胁到我的会话写作。

问题:

ASP.NET 会话管理如何使它如此容易受到此攻击?Response.Redirect() 代码行直到会话写入行“完成”才开始执行——它怎么会对我的会话写入造成如此大的威胁?

在下一行代码执行之前会话写入没有“完成”怎么办?是否存在会话写入类似(好像从未发生过)丢失的其他场景?

4

3 回答 3

2

我对会话编写的内部结构不够熟悉,但我想它有一些复杂性,因为它依赖于将浏览器会话 cookie 转换为服务器标识。此外,ThreadAbortExceptions在运行时确实有特殊考虑,可能会在这里发挥作用,我不确定。

在任何情况下,Response.Redirect()都有一个带有布尔参数的重载,可让您指定是否要结束线程。

Response.Redirect(string url,  bool endResponse);

如果您在 endResponse 设置为“false”的情况下调用它,它将优雅地完成,而不是在Thread.Abort()内部调用。但是,这意味着它还将在完成之前执行页面生命周期中剩余的任何代码。

一个很好的折衷办法是先Response.Redirect(url, false)调用Application.CompleteRequest(). 这将允许您的重定向发生,但也可以通过最少的额外生命周期处理优雅地关闭当前执行上下文。

于 2010-02-15T17:57:09.980 回答
1

在测试了几种替代方案(Response.Redirect(..., false)、Server.Transfer() 以及我现在想不起来的其他“解决方案”)之后,我们只找到了一个可靠的解决方案。

将我们的会话状态从 InProc 移动到 SqlServer 有效地从我们的系统中消除了这种行为,使 Response.Redirect(...) 完全可靠。如果进一步的测试显示其他情况,我会在这里报告,但我要说的是,为了让这种情况在您的环境中停止发生:将您的会话状态移动到 SqlServer(或者“脱离 InProc”是否足够好?我不确定)。

于 2010-11-22T16:05:48.250 回答
0

应用程序池回收可能会导致您的会话消失。您可以将应用程序池配置为在固定时间回收(推荐,在夜间或在低使用率期间)或增加应用程序池回收的超时期限。

于 2010-02-15T21:26:29.197 回答