今天,我们将新创建的 ASP.NET 应用程序部署到服务器,很快我们就意识到存在一个奇怪的安全相关问题,该问题导致应用程序崩溃。这是一个内部应用程序,我们使用模拟来管理用户访问资源的方式。但是,当用户尝试访问他们可以完全控制的文件夹时,应用程序会抛出“拒绝访问”异常。
该异常实际上是一个 AggregateException
并被抛出到一个使用 Parallel.ForEach
的方法中以枚举列表和主体内部,它尝试访问文件夹,但此时模拟上下文发生更改,工作线程作为应用程序池的身份运行,它无权访问该文件夹,因此出现异常。
为了确认这一点,我查看了 Parallel.ForEach
主体之前和内部的进程标识:
string before = WindowsIdentity.GetCurrent().Name;
Debug.WriteLine("Before Loop: {0}", before);
Parallel.ForEach(myList, currentItem =>
{
string inside = WindowsIdentity.GetCurrent().Name;
Debug.WriteLine("Inside Loop: {0} (Worker Thread {1})", inside, Thread.CurrentThread.ManagedThreadId);
});
当我运行该应用程序时,打印出以下内容:
Before Loop: MyDomain\ImpersonatedUser
Inside Loop: NT AUTHORITY\SYSTEM (Worker Thread 8)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 6)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 7)
Inside Loop: NT AUTHORITY\SYSTEM (Worker Thread 9)
Inside Loop: NT AUTHORITY\SYSTEM (Worker Thread 10)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 7)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 6)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 7)
如您所见,一些线程作为模拟身份运行,一些线程作为应用程序池(在本例中为 LocalSystem
)运行,似乎没有任何模式。 Call Stack
窗口中的前一帧也转到非托管 kernel32.dll
,这让我觉得 CLR 在将上下文委托(delegate)给操作系统之前没有验证上下文。
知道为什么会这样吗?这是一个已知问题/错误吗?
最佳答案
与 Task
类不同,Parallel
似乎没有捕获您当前正在运行的 ExecutionContext
(它反过来捕获SecurityContext
包含 WindowsIdentity
)。它使用当前线程中可用的那个。
您必须明确捕获所需的上下文:
IntPtr token = WindowsIdentity.GetCurrent().Token;
Parallel.ForEach(myList, currentItem =>
{
using (WindowsIdentity.Impersonate(token))
{
string inside = WindowsIdentity.GetCurrent().Name;
Debug.WriteLine("Inside Loop: {0} (Worker Thread {1})", inside, Thread.CurrentThread.ManagedThreadId);
}
});
关于c# - Parallel.ForEach() 更改模拟上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26065155/