日期:2014-05-17  浏览次数:20785 次

通过ACL和.net Framework实施对Windows对象访问的管理

通过ACL和.net Framework实施对Windows对象访问的管理
2010年12月08日
  作者:Mark Pustilnik http://msdn.microsoft.com/en-us/magazine/cc163885. aspx
  相关技术:安全、C#、.NET Framework     [摘要]本文介绍了.NET Framework 2.0中用于保护文件、目录、注册表项和其他对象的类,包括如何允许和禁止规则工作、安全设置的继承和传播,最后介绍了审核规则和对象所有权。
  注:本文基于.NET Framework 2.0(原来的代号为"Whidbey")的预发布版本。文中包含的所有信息均有可能变更。
  目前,形形色色的用户在本地以及通过网络使用计算机系统是已经是一种太常见的情况了。一些由用户产生的任何数据都必须保持隔离和私有,在很长一段时间内,多用户操作系统的设计人员已经意识到需要对文件、目录、同步对象、网络共享以及类似对象的访问进行控制。例如,在Windows中,登录到特定计算机的每个用户通常都分配有他自己单独的"我的文档"文件夹,并且被禁止读写其他用户的文件(除非进行了明确的规定)。可能要求学生用户将作业提交到某个目录中,同时禁止他们改动其内容或者查看其他学生的作业。出版公司可能具有只允许桌面出版部门的雇员访问彩色打印机的策略。对象安全并不限于单个对象,它有时适用于整个层次结构。例如,按照公司策略,我的开发计算机上的Windows源代码只能由Windows组织中的开发人员访问。要列出所有有关对象安全的应用几乎是不可能的。
  Windows系列操作系统已经在一段时期内提供了对保护对象的支持。该功能最开始出现在Windows NT中,并且在Windows的后续版本(Windows 2000、Windows XP和Windows Server 2003)中略有发展。如今,您可以保护NTFS文件和目录、打印机、网络共享、Active Directory??对象和内核对象……最常见的情况是,应用程序开发人员构建的新的安全方案与现有对象的安全性基于相同的技术集。例如,定义文件和Microsoft Exchange Server邮箱的安全性的访问控制列表(Access Control Lists,ACL)是非常类似的。老道的Windows开发人员非常熟悉对安全对象的Windows API支持,并且人们已经撰写了很多有关访问控制项(Access Control Entrie,ACE)、ACL、安全描述符和安全描述符定义语言(Security Descriptor Definition Language,SDDL)的文章。但是,尽管对象安全性具有很大的优势,但操纵安全设置仍然是一项相当困难的开发任务--即使Windows SDK逐渐引入了新的辅助函数,也是如此。所幸,.NET Framework 2.0提供了一种简单的、统一的且可扩展的方式来操纵文件的安全设置、注册表项、目录服务容器和其他对象。本文介绍了为Framework设计的新功能,并且通过代码示例对其进行了说明。     直到现在为止,Microsoft仍未在.NET Framework中提供对操纵安全设置的显式支持。使用.NET Framework 1.x,只能通过一系列麻烦的平台调用(P/Invoke)来授予用户访问权限。更糟糕的是,这不仅要求开发人员熟悉很多与Windows ACL和安全描述符有关的复杂细节,而且所得到的代码可能更易出现各种各样的编程错误,并且其中一些错误具有严重的安全问题。在这一领域内,您可以在任何应用程序中找到一些最严重的安全漏洞。在最能代表此类缺陷的示例中,很多读者可能会回忆起:在对象上设置NULL任意访问控制列表(Discretionary Access ControlList,DACL)会授予每个人完全访问权限,而空的DACL则不会授予任何人任何访问权限。.NET Framework 2.0使开发人员能够使用托管代码来操纵对象的安全设置,并且只需几个简单的步骤,它通过引入安全对象和规则的概念做到这一点。我将在本文中考察新加入的System.Security.AccessControl命名空间。我的大多数示例都将使用文件系统来进行说明。其他对象的保护方式与文件基本相同,但文件系统是最佳的说明对象,因为它同时包含叶子对象(文件)和容器对象(目录)。其他类型的资源管理器通常只具有其中一个类型的对象,例如,注册表是完全分层的,而互斥锁则不具有层次结构。 // Start by opening a file
  using(FileStream file = new FileStream(
  @"M:\temp\sample.txt", FileMode.Open, FileAccess.ReadWrite))
  {
  // Retrieve the file's security settings
  FileSecurity security = file.GetAccessControl();
  // Create a new rule granting Alice read access
  FileSystemAccessRule rule = new FileSystemAccessRule(
  new NTAccount(@"FABRIKAM\Alice"), FileSystemRights.Read,
  AccessControlType.Allow);
  // Add the rule to the existing rules
  security.AddAccessRule(rule);
  // Persist the changes
  file.SetAccessControl(security);
  } 图1 添加文件访问控制
  让我们首先考察如何授予对单个文件的访问权限。在新的方案中,通过在文件安全对象中添加和移除文件访问控制规则来控制对文件的访问(参见图1)。正如您可以看到的那样,更改文件的权限是用多个步骤完成的。首先,打开文件;然后,通过对GetAccessControl方法的调用来检索该文件的安全对象(类型为FileSecurity);除了包含其他内容以外,该对象还包含一组有序的访问规则,它们共同确定了各种用户和组对该文件所具有的权利。在该示例中,将一个新的访问规则添加到FileSecurity对象中,以便向Fabrikam域中名为Alice的用户授予对文件的访问权。在更改生效之前,必须将其持久保存在存储器中。最后这个步骤是通过调用SetAccessControl方法完成的。
  上一个示例说明了如何向现有对象的用户分配访问权。另一个同等重要的方案是在创建对象时,将该对象与安全设置相关联。将访问规则与全新的对象相关联,有一个重要的安全原因:可确保安全的对象总是用一些默认的安全语义创建的。默认情况下,分层式资源管理器(例如,文件系统或注册表)中的对象从其父对象中继承它们的安全设置,文件从它们的父目录中继承它们的安全设置,注册表项从它们的父项中继承它们的安全设置……相比之下,非分层式对象(例如,互斥锁或信号量)具有使用系统默认设置分配给它们的默认权利。默认权利取决于所创建对象的类型,而且可能不是您所希望的那样。例如,您很少会有意创建每个人都具有完全访问权限的对象,但这却可能恰好是默认安全设置所指定的权限。不能简单地用默认安全设置创建对象并且在以后修改这些设置,产生此问题的原因是,在已经创建对象之后对其加以保护会打开一个机会窗口(在创建和修改之间),在此期间该对象可能被劫持。劫持可能导致创建者失去对刚刚所创建对象的控制,这会造成灾难性的后果。图2说明了如何保护全新的对象: // Create a FileSecurity object
  FileSecurity security = new FileSecurity();
  // Create a new rule granting Alice read access
  FileSystemAccessRule rule = new FileSystemAccessRule(
  new NTAccount(@"FABRIKAM\Alice"), FileSystemRights.Read,
  AccessControlType.Allow );
  // Add the rule
  security.AddAccessRule(rule);
  // Create the file passing in the security settings
  FileStream file = new FileStream(
  @"M:\temp\sample.txt", FileMode