5

今天,我們將新創建的ASP.NET應用程序部署到服務器,很快我們意識到存在一個奇怪的安全相關問題,導致應用程序崩潰。這是一個內部應用程序,我們使用模擬來管理用戶訪問資源的方式。但是,應用程序在用戶試圖訪問完全控制的文件夾時會拋出「拒絕訪問」異常。Parallel.ForEach()更改模擬上下文

唯一的例外是實際上是一個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在將其委託給操作系統之前未驗證上下文。

任何想法爲什麼會發生這種情況?這是一個已知的問題/錯誤?

回答

3

不像Task類,Parallel似乎並沒有被捕獲ExecutionContext您當前運行(該系統在轉彎捕捉其持有WindowsIdentitySecurityContext)。它使用當前線程內的一個可用值。

你必須明確地捕捉到所需的環境下:

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

但爲什麼它確實似乎不是一種模式? – abatishchev 2014-09-26 17:53:23

+0

我不太確定。我以前見過有關這種方式的問題。看起來像*應該*被實現的特徵,因爲它是*期望*行爲。 – 2014-09-26 18:00:37

+0

是的,我使用'WindowsIdentity.GetCurrent()。Impersonate()'作爲解決方法,但我仍然不明白爲什麼線程之間存在差異。如果'SecurityContext'沒有被捕獲,那麼一些線程仍然作爲模擬身份運行?我覺得還有更多。 – PoweredByOrange 2014-09-26 18:02:41

0

Windows中的整個模擬的概念是每個線程的概念。 您會看到,當創建新線程時,它會繼承進程的權限令牌。 但是線程不像進程,也有一個模擬令牌。當您調用WindowsIdentity.Impersonate(令牌)時,您在調用線程上設置了模擬令牌。

另外,當您調用模擬時,您將線程的主令牌指針設置爲指向模擬令牌,而不是進程的主令牌,這是默認值。

在WinAPI中多一點理解和了解會導致您知道在您的服務中發生的事情是預期的行爲。

+2

少一點snark讓世界變得更美好,應該是預期的行爲。 – Loofer 2015-02-13 15:02:38