ASP.NET   身份模拟

身份和模拟
ASP.NET在一个工作进程中运行,在IIS 5.0中,该进程使用Windows账户ASPNET (没有句点)的凭证。在IIS 6.0中,该进程使用账户Network Service。为了安全起见,最好使用最少的权限运行ASP.NET,这是在设计ASP.NET时指定的。
在默认情况下,ASP.NET账户对所有的ASP.NET页面都具有Read & Execute权限。例如,在aspx页面属性的Security选项卡上,可以看到ASPNET和Network Service账户没有列出来。只列出了Everyone账户,它有Read & Execute权限,如图20-11所示。
图  20-11
如果从列表中删除这个账户,ASP.NET就不能运行页面。至少要给ASPNET或Network Service(取决于是运行IIS 5.0还是IIS 6.0)提供页面的Read & Execute权限。还必须确保IUSR_MachineName账户有访问同一页面的权限。
默认情况下,ASP.NET运行在权限有限的账户下。例如,尽管账户可以访问网络,但不能在网络的其他计算机上进行验证。
账户设置在machine.config文件中进行:
<processModel
 enable="true"
 userName="machine"
 password="AutoGenerate" />
这些设置迫使ASP.NET运行在系统账户(ASPNET或Network Service)上。这是通过userName属性指定的,该属性的值是machine。这个属性的值还可以是system。下面是这两个值的详细说明:
●       machine:最安全的设置。最好不要修改这个值。它非常理想,因为它会强制ASP.NET账户在权限最少的情况下运行。
●       System:强制ASP.NET在本地SYSTEM账户下运行,它的权限要比访问网络和文件大得多。
还可以在machine.config文件或web.config文件中使用<processModel>元素指定账户:
<processModel
 enable="true"
 userName="MySpecifiedUser"
 password="MyPassword" />
在这个例子中,ASP.NET在指定的管理员或用户账户下运行,而不是在默认的ASPNET或Network Service账户下运行。它继承了这个账户提供的所有权限。应考虑对该文件的这个部分加密,配置文件的加密详见第31章。
使用web.config文件中的<identity>元素,无论ASP.NET在哪个指定的账户下运行,都可以改变ASP.NET的运行方式。web.config文件中的<identity>元素允许启用模拟功能。模拟功能可以让ASP.NET为某个会话使用另一个用户的权限作为一个进程运行。更具体地说,就是模拟功能允许ASP.NET在向应用程序发出请求的实体账户下运行。要启用这个模拟功能,可以使用<identity>元素的impersonate属性,如下所示:
<configuration>
   <system.web>
      <identity impersonate="true" />
   </system.web>
</configuration>
默认情况下,impersonate属性设置为false。把这个属性设置为true,将确保ASP.NET运行在向应用程序发出请求的用户账户下。如果请求者是一个匿名用户,ASP.NET就运行在IUSR_MachineName账户下。为了演示这一点,运行程序清单20-18的例子,但这次启用模拟功能(true)。此时我们获得的用户名不是REUTERS-EVJEN/ASPNET,而是请求页面的用户的名称REUTERS-EVJEN/Administrator,如图20-12所示。
图  20-12
还可以使用web.config文件中的<identity>元素,使ASP.NET在指定的账户下运行:
<identity impersonate="true" userName="MySpecifiedUser" password="MyPassword" />
如上所示,通过userName和password属性,可以在指定的账户下运行ASP.NET进程。这些值在web.config文件中存储为明文。
查看machine.config.comments文件,可以看到ASP.NET在完全可信的级别下运行,也就是说,它利用一些高级功能来运行和访问资源。下面是设置:
<system.web>
  
   <securityPolicy>
      <trustLevel name="Full" policyFile="internal" />
      <trustLevel name="High" policyFile="web_hightrust.config" />
      <trustLevel name="Medium" policyFile="web_mediumtrust.config" />
      <trustLevel name="Low"  policyFile="web_lowtrust.config" />
      <trustLevel name="Minimal" policyFile="web_minimaltrust.config" />
   </securityPolicy>
   <!--  level="[Full|High|Medium|Low|Minimal]" -->
   <trust level="Full" originUrl="" />
</system.web>
可以给ASP.NET的信任级别指定5个设置:Full、High、Medium、Low和Minimal。信任级别通过<trust>元素的level属性指定。它默认设置为Full。每个信任级别都指向一个特定的策略配置文件,在该文件中,可以找到它的信任级别设置。Full设置不包含策略文件,因为它跳过了所有的代码访问安全检查。
摘要
缺省情况下,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.WindowsImpersonationContext
Dim currentWindowsIdentity As System.Security.Principal.WindowsIdentity
currentWindowsIdentity = 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  = 2
Dim LOGON32_PROVIDER_DEFAULT As Integer = 0

Dim impersonationContext As WindowsImpersonationContext

Declare 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 Integer
Declare Auto Function DuplicateToken Lib "advapi32.dll"(ByVal ExistingTokenHandle As IntPtr, _
                           ImpersonationLevel As Integer, _
                           ByRef DuplicateTokenHandle As IntPtr) As Integer

Public 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 If
End Sub

Private 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 If
End Function

Private 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" />
来执行该程序。

更多信息
请访问以下链接获取更多信息:
1. INFO: Implementing Impersonation in an ASP.NET Application
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158&SD=MSKB&#1
2. INFO: ASP.NET Security Overview
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306590
3. ASP.NET Web Application Security
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconaspnetwebapplicationsecurity.asp

作者:黄雪斌

 

使用模拟时,ASP.NET 应用程序可以选择以这些应用程序当前正为之操作的客户的身份执行。通常这样做的原因是为了避免在 ASP.NET 应用程序代码中处理身份验证和授权问题。而您依赖于 Microsoft Internet 信息服务 (IIS) 来验证用户,然后将已通过验证的标记传递给 ASP.NET 应用程序;或者,如果无法验证用户,则传递未经身份验证的标记。不论何种情况,如果启用了“模拟”,则 ASP.NET 应用程序会模拟所收到的任何标记。当前模拟客户的 ASP.NET 应用程序依赖于 NTFS 目录和文件中的设置来允许客户获得访问权限或拒绝其访问。务必将服务器文件空间格式化为 NTFS,以便可以设置访问权限。

默认情况下禁用模拟。为了 ASP 的兼容性,用户必须显式启用模拟。如果为给定的应用程序启用模拟,则 ASP.NET 总是模拟 IIS 提供给 ISAPI 扩展的访问标记。该标记既可以是已验证用户标记,也可以是匿名用户的标记(如 IUSR_MACHINENAME)。不论应用程序中使用哪种身份验证类型,模拟都会发生。

只能模拟应用程序代码,编译和配置作为进程标记读取。编译的结果放在“Temporary ASP.NET files”目录中。所模拟的帐户需要对该目录的读/写访问权。如果应用程序位于通用命名规则 (UNC) 共享上,除非使用配置帐户,否则,ASP.NET 将总是模拟提供给 IIS 的标记来访问该共享。如果提供了显式配置的帐户,ASP.NET 将使用该帐户取代 IIS UNC 标记。确实需要基于每个请求的模拟的应用程序可以直接配置为模拟提交请求的用户。

默认情况下,在计算机级别上禁用模拟。而且除非被重写,否则所有的应用程序域都继承此设置。可以通过将配置文件放置在应用程序根目录下来启用模拟。有关 ASP.NET 配置系统的更多信息,请参见 ASP.NET 配置。

与其他配置指令的情况相同,此指令分层应用。除非被显式重写,否则,层次结构中的嵌套程序将遵从它。此设置的默认值如下所示。

<impersonation enable="false"/>

为应用程序启用模拟的最小配置文件可能看上去和下面的示例类似。

<!-- Web.config file. -->
<identity impersonate="true"/>

还有以可配置身份运行应用程序的名称支持。例如:

<identity impersonate="true" userName="contoso/Jane" password="pass"/>

这将允许整个应用程序以 contoso/Jane 运行,不论请求的身份如何,只要密码正确即可。可以将这种类型的模拟委托给另一台计算机。

您可以以编程的方式读取被模拟用户的标识,如下例所示。

[Visual Basic]
Dim username As String = System.Security.Principal.WindowsIdentity.GetCurrent().Name

[C#]
String username = System.Security.Principal.WindowsIdentity.GetCurrent().Name;

在上例中,userName 和 password 以明文形式存储在配置文件中。虽然 IIS 不传输 .config 文件来响应用户代理请求,但是可以通过其他途径读取配置文件,例如通过在包含服务器的域上具有适当凭据的已经过身份验证的用户。为了增强安全性,标识部分支持在注册表中存储加密的 userName 和 password 属性,如下例所示。

   userName="registry:HKLM/Software/AspNetIdentity,Name"
   password="registry:HKLM/Software/AspNetIdentity,Password"

字符串中位于关键字 registry 之后和逗号之前的部分表示 ASP.NET 打开的注册表项的名称。逗号之后的部分包含一个字符串值的名称,ASP.NET 从此名称中读取凭据。必须有逗号,并且凭据必须存储在 HKLM 配置单元中。如果配置格式不正确,则 ASP.NET 不会启动辅助进程,然后将显示造成当前帐户创建失败的代码路径。

凭据必须为 REG_BINARY 格式,并且包含 Windows API 函数 CryptProtectData 调用的输出。可以用 ASP.NET 设置注册表控制台应用程序 (Aspnet_setreg.exe) 来创建加密凭据并将它们存储在注册表中。该应用程序使用 CryptProtectData 完成加密。若要同 Visual C++ 源代码和文档一起下载 Aspnet_setreg.exe,请访问 Web 站点 www.asp.net 并搜索“aspnet_setreg”。

应该对存储加密凭据的密钥的访问权限进行配置,仅向 Administrators 和 SYSTEM 提供访问权。由于密钥会被作为 SYSTEM 运行的 ASP.NET 进程读取,因此应设置以下权限:

Administrators:F
SYSTEM:F
CREATOR OWNER:F
ProcessAccount:R
这可以提供两道保护数据的防线:

ACL 权限要求访问数据的身份是 Administrator。
攻击者必须在服务器上运行代码 (CryptUnprotectData) 才能恢复帐户的凭据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值