Windows的用户管理中的用户模拟 收藏
用户模拟(Impersonation)是自从Windows 2000时引入的强大的功能。Windows系统甚至允许用户模拟(Impersonation)被用在客户端/服务端的编程模型里面。
在传统模式下,比如一个远程服务器可以提供文件、打印机或者数据库服务,希望使用这些资源的客户端可以发送一个请求给远程服务器,这时候,远程服务器必须要确保客户端有权限来访问它请求的资源,于是远程服务器查询用户的帐号和组信息,然后查询资源的安全描述符来判断资源访问是否被允许。这个过程需要大量的编码,并且非常容易出错,而且也不能自动整合后续版本操作系统带来的新的安全特性。因此Windows 2000起,我们可以使用用户模拟(Impersonation)来简化这个问题—比如IIS里面就使用到了用户模拟(Impersonation)功能。
比如,我们在局域网里面新建了一个网站,局域网用户可以使用这个网站上传自己的图片,编辑自己的文件,并且可以跟自己的好友共享这些图片和文件。网站使用Windows验证方式,这样就省去了局域网用户登录网站的麻烦。就是说如果用户打开IE访问网站的时候,直接就获得了相应的访问权限—这也是SharePoint Server使用的用户身份验证方式。另外在设计的时候,为了得到更大的可扩展性,图片和文件不是保存在数据库里面的,而是直接保存在文件系统(也许是分布式文件系统)里面的。也即是说,当新建了一个用户A的时候,
1. 网站就在域里面新建一个用户A,还创建了一个用户组A’s Friend—用来保存用户A的好友帐号;
2. 并且在保存图片和文件的分布式文件系统里面创建了一个文件夹A,这个文件夹A有读写权限,而A’s Friend只有读的权限,其他用户默认没有任何权限。
当A在浏览器里面上传图片,网站接受图片并且把图片保存到文件夹A里面。这样就为网站的实现提出了一个难题,即网站ASP.NET程序以什么用户身份运行?
n 如果以域管理员帐号运行的话,那么无疑带来了很大的安全方面的风险,因为域管理员帐号在域里面的控制权可以说是无限大的,如果你的网站代码没有考虑到一些网络攻击—很容易就造成整个域瘫痪掉。
n 而如果以其他的帐号运行,又怎么保证网站有权限将用户A上传的图片保存到文件夹A里面去?
这种情形,你就可以使用用户模拟(Impersonation)功能,网站只要运行在最低权限—例如Network Service用户下面,当需要保存用户A上传的图片时,网站所要做的就是获取用户A的登录信息暂时模拟用户A,将图片保存到文件夹A中后,回滚用户模拟(Impersonation)操作,重新让网站运行在最低权限下。这样既做到系统的可扩展性,又做到了将安全风险降到最低的目标。这种权限验证方式省却了重复实现安全子系统的努力,而将用户权限管理集成到Windows域管理系统里面,另外系统的可扩展性也解决了,因为据测试,Windows的Active Directory可以支持上亿用户—好像没有几个局域网能有这么多的用户吧?
远程服务器通过在线程里面要求用户模拟(Impersonation)来模拟一个用户。线程的访问令牌(Access Token)包含了模拟信息(Impersonation Token),并且还包含了线程的真实安全凭据(Security Credential),因此在模拟完一个用户以后,线程还能重新使用自己实际的访问令牌(Access Token) 。
为了避免远程服务器滥用用户模拟(Impersonation)功能,Windows系统允许客户端对用户模拟(Impersonation)进行一系列的限制:
限制类型
说明
SECURITY_ANONYMOUS
最严格的限制—远程服务器不能模拟客户端的用户身份
SECURITY_IDENTIFICATION
允许远程服务器获取客户端用户的安全身份标识符(SID)和用户的权限信息,但是服务器不能模拟用户身份。
SECURITY_IMPERSONATIONN
允许远程服务器在访问本机资源的时候模拟用户身份
SECURITY_DELEGATION
允许远程服务器在访问本机和远程机资源的时候模拟用户身份
如果客户端不进行限制,那么默认远程服务器具有SECURITY_IMPERSONATIONN权限,即可以在访问本机资源的时候模拟用户身份。
用户模拟的代码:
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
IntPtr tokenHandle = IntPtr.Zero;
bool returnValue = LogonUser(userName, domainName, password.ToString(),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
Console.WriteLine("Before impersonation: "
+ WindowsIdentity.GetCurrent().Name);
WindowsIdentity identity = new WindowsIdentity(tokenHandle);
WindowsImpersonationContext impersonatedUser = identity.Impersonate();
Console.WriteLine("After impersonation: "
+ WindowsIdentity.GetCurrent().Name);
impersonatedUser.Undo();
Console.WriteLine("After Undo: " + WindowsIdentity.GetCurrent().Name);
if (tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Donjuan/archive/2009/02/06/3866799.aspx