1. 程式人生 > >在ASP.NET應用程式中使用身份模擬(Impersonation)

在ASP.NET應用程式中使用身份模擬(Impersonation)

摘要 預設情況下,ASP.NET應用程式以本機的ASPNET帳號執行,該帳號屬於普通使用者組,許可權受到一定的限制,以保障ASP.NET應用程式執行的安全。但是有時需要某個ASP.NET應用程式或者程式中的某段程式碼執行需要特定許可權的操作,比如某個檔案的存取,這時就需要給該程式或相應的某段程式碼賦予某個帳號的許可權以執行該操作,這種方法稱之為身份模擬(Impersonation)。本文介紹了在ASP.NET應用程式中使用身份模擬的幾種方法,並比較了它們各自適用的範圍。 在閱讀本文之前,建議您先閱讀文章:《ASP .NET 中的身份驗證:.NET 安全性指導》 以便對ASP.NET的安全控制有一個總體的瞭解。 目錄
  • ASP.NET中的身份模擬
  • 模擬IIS認證帳號
  • 在某個ASP.NET應用程式中模擬指定的使用者帳號
  • 在程式碼中模擬IIS認證帳號
  • 在程式碼中模擬指定的使用者帳號
  • 更多資訊
ASP.NET中的身份模擬 ASP.NET 通過使用身份驗證提供程式來實現身份驗證,一般情況下,ASP.NET的身份驗證提供程式包括表單身份驗證、Windows身份驗證和Passport身份驗證3種。當通過身份驗證後,ASP.NET會檢查是否啟用身份模擬。如果啟用,ASP .NET 應用程式使用客戶端標識以客戶端的身份有選擇地執行。否則,ASP.NET應用程式使用本機身份標識執行(一般使用本機的ASPNET帳號),具體流程如下圖所示:

在ASP.NET應用程式中使用身份模擬一般用於資源訪問控制,主要有如下幾種方法:
  • 模擬IIS認證帳號
  • 在某個ASP.NET應用程式中模擬指定的使用者帳號
  • 在程式碼中模擬IIS認證帳號
  • 在程式碼中模擬指定的使用者帳號
模擬IIS認證帳號 這是最簡單的一種方法,使用經過IIS認證的帳號執行應用程式。您需要在Web.config檔案中新增<identity>標記,並將impersonate屬性設定為true:
<identity impersonate="true" />
在這種情況下,使用者身份的認證交給IIS來進行。當允許匿名登入時,IIS將一個匿名登入使用的標識(預設情況下是IUSR_MACHINENAME)交給ASP.NET應用程式。當不允許匿名登入時,IIS將認證過的身份標識傳遞給ASP.NET應用程式。ASP.NET的具體訪問許可權由該賬號的許可權決定。 模擬指定的使用者帳號 當ASP.NET應用程式需要以某個特定的使用者帳號執行,可以在Web.config檔案的<identity>標記中指定具體的使用者帳號:
<identity impersonate="true" userName="accountname" password="password" />
這時該ASP.NET應用程式的所有頁面的所有請求都將以指定的使用者帳號許可權執行。 在程式碼中模擬IIS認證帳號 在程式碼中使用身份模擬更加靈活,可以在指定的程式碼段中使用身份模擬,在該程式碼段之外恢復使用ASPNET本機帳號。該方法要求必須使用Windows的認證身份標識。下面的例子在程式碼中模擬IIS認證帳號: Visual Basic .NET
Dim impersonationContext As System.Security.Principal.WindowsImpersonationContextDim currentWindowsIdentity As System.Security.Principal.WindowsIdentitycurrentWindowsIdentity = CType(User.Identity, System.Security.Principal.WindowsIdentity)impersonationContext = currentWindowsIdentity.Impersonate()'Insert your code that runs under the security context of the authenticating user here.impersonationContext.Undo()
Visual C# .NET
System.Security.Principal.WindowsImpersonationContext impersonationContext;impersonationContext = ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();//Insert your code that runs under the security context of the authenticating user here.impersonationContext.Undo();
在程式碼中模擬指定的使用者帳號 下面的例子在程式碼中模擬指定的使用者帳號: Visual Basic .NET
<%@ Page Language="VB" %><%@ Import Namespace = "System.Web" %><%@ Import Namespace = "System.Web.Security" %><%@ Import Namespace = "System.Security.Principal" %><%@ Import Namespace = "System.Runtime.InteropServices" %><script runat=server>Dim LOGON32_LOGON_INTERACTIVE As Integer  = 2Dim LOGON32_PROVIDER_DEFAULT As Integer = 0Dim impersonationContext As WindowsImpersonationContextDeclare Auto Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As String, _                           ByVal lpszDomain As String, _                           ByVal lpszPassword As String, _                           ByVal dwLogonType As Integer, _                           ByVal dwLogonProvider As Integer, _                           ByRef phToken As IntPtr) As IntegerDeclare Auto Function DuplicateToken Lib "advapi32.dll"(ByVal ExistingTokenHandle As IntPtr, _                           ImpersonationLevel As Integer, _                           ByRef DuplicateTokenHandle As IntPtr) As IntegerPublic Sub Page_Load(s As Object, e As EventArgs)   If impersonateValidUser("username", "domain", "password") Then      'Insert your code that runs under the security context of a specific user here.      undoImpersonation()   Else      'Your impersonation failed. Therefore, include a fail-safe mechanism here.   End IfEnd SubPrivate Function impersonateValidUser(userName As String, _domain As String, password As String) As Boolean    Dim tempWindowsIdentity As WindowsIdentity   Dim token As IntPtr   Dim tokenDuplicate As IntPtr   If LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, _                LOGON32_PROVIDER_DEFAULT, token) <> 0 Then      If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then                 tempWindowsIdentity = new WindowsIdentity(tokenDuplicate)                impersonationContext = tempWindowsIdentity.Impersonate()                      If impersonationContext Is Nothing Then                   impersonateValidUser = False                Else    	           impersonateValidUser = True                End If      Else	        impersonateValidUser = False      End If   Else      impersonateValidUser = False   End IfEnd FunctionPrivate Sub undoImpersonation()   impersonationContext.Undo()End Sub</script>
Visual C# .NET
<%@ Page Language="C#"%><%@ Import Namespace = "System.Web" %><%@ Import Namespace = "System.Web.Security" %><%@ Import Namespace = "System.Security.Principal" %><%@ Import Namespace = "System.Runtime.InteropServices" %><script runat=server>public const int LOGON32_LOGON_INTERACTIVE = 2;public const int LOGON32_PROVIDER_DEFAULT = 0;WindowsImpersonationContext impersonationContext; [DllImport("advapi32.dll", CharSet=CharSet.Auto)]public static extern int LogonUser(String lpszUserName,                                   String lpszDomain,                                  String lpszPassword,                                  int dwLogonType,                                   int dwLogonProvider,                                  ref IntPtr phToken);[DllImport("advapi32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto, SetLastError=true)]public extern static int DuplicateToken(IntPtr hToken,                                   int impersonationLevel,                                    ref IntPtr hNewToken);public void Page_Load(Object s, EventArgs e){   if(impersonateValidUser("username", "domain", "password"))   {      //Insert your code that runs under the security context of a specific user here.      undoImpersonation();   }   else   {      //Your impersonation failed. Therefore, include a fail-safe mechanism here.   }}private bool impersonateValidUser(String userName, String domain, String password){   WindowsIdentity tempWindowsIdentity;   IntPtr token = IntPtr.Zero;   IntPtr tokenDuplicate = IntPtr.Zero;   if(LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE,    LOGON32_PROVIDER_DEFAULT, ref token) != 0)   {      if(DuplicateToken(token, 2, ref tokenDuplicate) != 0)       {         tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);         impersonationContext = tempWindowsIdentity.Impersonate();         if (impersonationContext != null)            return true;         else            return false;       }      else         return false;   }    else      return false;}private void undoImpersonation(){     impersonationContext.Undo();} </script>
下面介紹ASP.NET應用程式中使用身份模擬的一個簡單應用。例如有一個ASP.NET應用程式要檢查伺服器端某個檔案是否存在,相應的程式程式碼為:
bool a = File.Exists("D://Share//test.txt");
預設情況下該ASP.NET應用程式以ASPNET帳號執行。為了安全起見,ASPNET這個帳號並沒有伺服器端D:/Share/這個目錄的訪問許可權。在不使用身份模擬的情況下,由於ASP.NET應用程式不具有訪問該目錄的許可權,無論檔案是否存在,File.Exists的返回值將永遠是false。為了解決這個問題,可以另建一個使用者帳號:FileExist,並賦予該帳號D:/Share/目錄的訪問許可權。然後在該應用程式的Web.config檔案的<identity>標記中指定具體的使用者帳號:
<identity impersonate="true" userName="FileExist" password="password" />
來執行該程式。