授权

 

目的 Purpose

授权是指使用系统以及系统中的数据的权利的赋予。授权一般由系统管理员设置、并由计算机根据用户的身份,比如代码数字、密码,来进行区分。

微软的授权包括授权管理和授权API两部分。

面向的开发者受众 Developer audience

微软的授权技术是为那些基于Windows Server和控制访问资源的操作系统开发应用程序的开发者设计的。开发者需要熟悉Windows编程,尽管没有要求、但是对授权或者安全相关的主题的理解是有益的。

运行时要求 Run-time Requirements

这个可以学习参考文档中的相关内容获得详细资料。

 

PS: MSDN里面的文档分的太细了,如果用缩进的方式分开章节,那么有的章节就会缩到文本的一半距离,所以我想了用颜色来区分章节的办法(黑、红、蓝按二级章节交替,Blue is my Favorite)。

 

1. 关于授权 About Authorization

1.1 访问控制 Access Control

      访问控制指的是控制谁可以访问操作系统资源的安全特性,应用程序调用访问控制函数来设置谁可以访问指定的资源、或者控制对应用程序提供的资源的访问。

 

      这个概览描述了一个安全模型,即控制对例如文件等的Windows对象的访问和控制用户对一些功能例如设置系统时间的访问、或者审核用户的行为。访问控制模型提供了一个关于访问控制各部分的高级描述,还有它们之间如何相互影响。

 

1.1.1 C2级别安全 C2-level Security

      下面列举了美国国防部定义的C2级别中一些最重要的安全要求:

  • 要可以控制赋予和否决个人用户或者组用户对资源的访问
  • 要保护内存,以使进程释放了内存之后它不能读取它的内容;同样的,一个安全的文件系统,比如NTFS,要保证正在读取的文件不能被删除。
  • 用户登录的时候必须可以用唯一的方式标识自己的身份,比如密码。所有的审核操作必须可以识别用户作出的操作。
  • 系统管理员一定要可以审核安全相关的事件,同时,访问安全相关事件的审核数据仅限于获得授权的管理员。
  • 系统必须可以防止外部干扰和篡改,例如对运行中系统和磁盘上系统文件的修改。

1.1.2 访问控制模型 Access Control Models

      访问控制模型允许你控制进程访问安全对象的能力以及完成不同系统管理员任务的能力,下面的这些主题提供了访问控制模型的详细描述,还有它们之间是如何相互影响的。

1.1.2.1 访问控制模型的各部分 Parts of the Access Control Model

      访问控制模型有两个重要组成部分:

  • 访问令牌(access token):包含了登录用户的信息
  • 安全描述符(security descriptors):包含了保护安全对象的安全信息

      一个用户登录时,系统会给用户账户名字和密码授权。如果登录成功了,系统就创建一个访问令牌。每一个代表该用户执行的进程都有一份该访问付符的副本。这个访问令牌 包含了用来确认用户账户和用户属于哪一个组账户的安全描述符。这个访问令牌 还包含了用户或者用户所在组的一个特权列表。在一个进程尝试访问一个安全对象或者是执行要求特权的系统管理任务时,系统就通过该访问令牌 来进行确认。

      当一个安全对象创建时,系统就赋予它一个安全描述符,其中包含了它的创建者指定的安全信息,或者,如果没有指定用户,就会是一个默认的安全信息。应用程序可以使用函数得到或者设置一个存在的对象的安全信息。

      一个安全描述符可以识别对象的拥有者、并且还可以包含下列访问控制列表(ACLs):

  • 一个DACL(discretionary  access control list),用来识别用户或组应该允许还是拒绝访问指定对象。
  • 一个SACL(system access control list),控制系统如何审核对指定对象的访问尝试。

      一个ACL包含了一个ACEs(access control entries)列表,每一个ACE包含了一组访问权限和一个标识应该允许、拒绝、还是审核某个受托对象(Trustee)的SID,所谓受托对象可以是一个用户账户、组账户、或者是一个登陆会话。

      最好使用函数来操作安全描述符、SIDs、ACLs这些对象的内容,而不要直接访问它们。因为这样可以保证这些对象的语法结构的准确性,并且在将来加强安全系统之后不影响已存在的代码。

      以下8个小节讲述访问模型的部分知识点:

1.1.2.1.1 访问令牌 Access Tokens

      访问令牌 是一个用来描述进程或者线程的安全上下文的对象。访问令牌 中的信息包含了与进程或者线程相关的用户的ID和特权。当用户登录的时候,系统对用户的密码和保存在安全数据库中的信息作比较,从而验证用户身份。如果密码通过验证,系统就生成一个访问令牌 ,之后由该用户运行起来的进程都有一份这个访问令牌 的副本。

      当一个线程和一个安全对象进行交互,或者尝试执行一个有特权要求的系统任务的时候,系统通过访问令牌 来识别用户的身份。访问令牌 包含了以下信息:

  • 用户账户的安全身份SID
  • 用户所属用户组的安全身份SIDs
  • 标识当前登录会话的登录安全身份SID
  • 用户或者用户所在组的一个特权列表
  • 拥有者的SID
  • 主要用户组的SID
  • 默认访问控制列表DACLs,当用户创建安全对象的时候未设置安全描述符,系统就会使用DACLs
  • 访问令牌 的源
  • 该访问令牌 是主要访问令牌 还是模拟访问令牌
  • 一个可选的限制安全身份SIDs
  • 当前模拟的级别Impersonation Level
  • 其他统计数据

      每一个进程都有一个主访问令牌 用来描述和用户相关的进程的安全上下文,默认情况下,当进程中的线程和安全对象交互的时候,系统要用到主访问令牌 。另外,一个线程可以模拟一个客户账号,模拟操作允许线程使用这个客户的安全上下文来和安全对象进行交互,这时候,模拟客户账号的线程同时拥有主访问令牌 和模拟访问令牌 。

      使用函数OpenProcessToken可以得到进程主访问令牌 的句柄;使用函数OpenThreadToken可以得到线程的模拟访问令牌 句柄。更多信息参考1.3.2客户模拟。

      你可以使用下面的函数来控制访问令牌 :

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      上面的访问令牌 操作函数使用下列结构体来描述访问令牌 。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      访问令牌 操作函数使用下面的枚举类型

 

 

 

 

 

 

 

1.1.2.1.1.1 限制访问令牌 Restrict Tokens

      一个限制访问令牌是由函数CreateRestrictedToken函数修改的主要访问令牌或者模拟访问令牌。如果一个进程或者模拟线程运行在一个限制访问令牌的安全上下文中的话,那么这个进程/线程访问安全对象或者使用特权的能力将有所限制。函数CreateRestrictedToken将通过下面的方式限制一个访问令牌:

  • 去除访问令牌中的特权
  • 将禁用属性应用到访问令牌中的安全身份SIDs中,以便它们不能访问安全对象,关于禁用属性的详细信息参考 1.1.2.1.1.2 访问令牌的SID属性 小节
  • 指定一个限制SIDs列表,用来限制对安全对象的访问

      当系统检查令牌对一个安全对象的访问权限的时候就会用到这个限制SIDs列表。当一个限制权限的进程/线程尝试访问安全对象的时候,系统执行两次访问检查:一次是使用访问令牌中开启的SIDs,一次是使用限制SIDs列表。仅当两次检查的结果都允许请求的访问权限时才赋予访问权限,关于访问检查的详情参考1.1.2.2 访问检查是如何工作的。

      你可以在CreateProcessAsUser函数调用中使用一个限制的主要访问令牌,一般来说,调用CreateProcessAsUser函数的进程必须拥有SE_ASSIGNPRIMARYTOKEN_NAME特权,这个特权通常是由系统代码或者运行在本地系统账户的服务拥有。但是,如果CreateProcessAsUser调用指定的是一个调用者的限制版本的主要访问令牌,那么是不需要这个特权的。这使得普通程序可以创建限制权限的进程(Restricted Processes)。

      你也可以在ImpersonatedLoggedOnUser函数中使用限制版本的主要访问令牌和模拟访问令牌。

      调用IsTokenRestricted函数,可以检查一个访问令牌是否包含一个限制SIDs列表。

注释:使用限制访问令牌的应用程序应该运行在限制程序的桌面,而不是默认的桌面。这样做很有必要的,可以防止限制程序使用SendMessage、PostMessage对默认桌面上运行的非限制的应用程序进行攻击。如果需要你应该根据需求在两种桌面之间进行切换。

 

1.1.2.1.1.2 访问令牌中的SID属性 SID Attributes in an Access Token

      访问令牌中的每一个用户和组的安全身份SID都有一组属性,它们可以控制系统如何在一次访问检查中使用SID,下面的表中列举了控制访问检查的属性。

 

 

 

 

 

 

      要设置或者清除一个组SID的SE_GROUP_ENABLED属性,可以使用AdjustTokenGroups函数。你不能关闭一个带有SE_GROUP_MANDATORY属性的组SID,你不能使用AdjustTokenGroup来关闭访问令牌的用户SID。

      要想知道访问令牌中的一个SID是否开启,具体地说就是是否带有SE_GROUP_ENALBED,可以调用CheckTokenMemberShip函数。

      当你调用CreateRestrictedToken的时候,要设置一个SID的SE_GROUP_USE_FOR_DENY_ONLY属性,它是一个禁用SIDs列表中的一个SID。CreateRestrictedToken可以给任何SID设置SE_GROUP_USE_FOR_DENY_ONLY属性,包括带有SE_GROUP_MANDATORY属性的用户SID和组SIDs。但是你不能对一个SID移除禁用的属性,也不能使用AdjustTokenGroups来对一个SID设置SE_GROUP_ENABLED属性。

      要得到一个SID的属性,可以调用带有TokenGroups值的GetTokenInformation函数。这个函数返回一组标识了用户组SIDs和他们的属性值得SID_AND_ATTRIBUTES结构。

 

1.1.2.1.1.3 访问令牌对象的访问权限 Access Rights for Access Token Objects

      一个应用程序一般不能改变一个对象的访问控制列表,除非它有这个权限。这些权限由访问令牌中的安全描述符控制。关于安全的详情参考1.1.2访问控制模型。

      要设置或者得到一个访问令牌中的安全描述符,可以调用GetKernelObjectSecurity和SetkernelObjectSecurity函数。

      当你调用OpenProcessToken或者OpenThreadToken得到一个访问令牌的时候,系统检查需要的访问权限和在访问令牌中安全描述符的DACL。

      下面是访问令牌对象有效的访问权限:

  • DELETE、READ_CONTROL、WRITE_DAC和WRITE_OWNER这些标准访问权限,访问令牌不支持SYNCRONIZE标准访问权限
  • ACCESS_SYSTEM_SECURITY权限,得到或者设置一个对象的安全描述符中的SACL
  • 访问令牌中特定的访问权限,这些权限列于下表:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1.2.1.2 安全描述符 Security Descriptors

      安全描述符包含和安全对象相关的安全信息,一个安全描述符由SECURITY_DESCRIPTOR结构和相关的安全信息组成。一个安全描述符可以包含以下安全信息:

  • 一个对象的拥有者和所属主要用户组的安全身份SIDs
  • 一个DACL,这个DACL说明了允许还是禁止对特定用户(组)的访问权限
  • 一个SACL,这个SACL指定了为对象生成的审核记录的访问尝试的类型
  • 一组控制bit位,这组bit位用来检查一个安全描述符和它的私有成员所代表含义的资格

      应用程序不能直接操作安全描述符。Windows API提供了一组函数来设置和返回一个对象的安全描述符的安全信息。另外,还有一些函数用来创建和初始化一个新对象的安全描述符。

      操作活动目录对象安全描述符的应用程序会使用Windows的安全函数或者由ADSI(活动目录服务接口)提供的安全接口,关于ADSI的详情可以参考对活动目录域名服务的访问控制是如何工作的

 

1.1.2.1.2.1 安全描述符的操作 Security Descriptor Operations

      Windows API提供了对安全对象的安全描述符进行设置和获取操作的函数。使用GetSecurityInfo和GetNamedSecurityInfo函数可以得到一个对象的安全描述符。这些函数也可以返回安全描述符的私有部分:DACL、SACL、拥有者SID和主要用户组SID。使用SetSecurityInfo和SetNamedSecurityInfo可以设置一个对象的安全描述符信息。

      一般来说,你可以使用GetSecurityInfo和SetSecurityInfo操作由句柄标识的对象,并通过SetSecurityInfo和SetNamedSecurityInfo来设置由一个名字标识的对象。关于对不同类型的对象使用哪些函数可以参考 1.1.6 安全对象。

      Windows API还提供了一些辅助函数用来操作一个安全描述符的子部分,关于如何处理访问控制列表,可以参考 1.1.2.1.3.1 获取ACL信息 和 创建和修改ACL。关于SID的详情可以参考1.1.2.1.7 安全身份。

      要得到一个安全描述符的控制信息,调用GetSecurityDescriptorControl函数;要设置一个和自动继承ACE相关的控制位bit,调用SetSecurityDescriptorControl函数;其他的控制位bit由不同的设置安全描述符子部分的函数操作。比如说如果你你调用SetSecurityInfo函数来改变一个对象的DACL,函数会设置或者清空相应的bit位来表示一个安全描述符是否有一个DACL,是否是一个默认的DACL等等,另一个例子是安全描述符中的资源管理器RM控制位,这些控制位bit根据资源管理管理器的实现分别有不同的用处,也可以用函数GetSecurityDescriptorRMControl和SetSecurityDescriptorRMControl来操作这些控制位bit。

 

1.1.2.1.2.2 新对象的安全描述符 Security Descriptors for New Objects

      当你创建一个新的安全对象的时候,你可以为这个对象赋予一个安全描述符。比如说CreateFile、RegCreateKeyEx用来创建安全对象的函数,都有一个指向一个SECURITY_ATTRIBUTES结构的参数,这个参数可以包含这个新对象的安全描述符。有一个演示了创建一个安全描述符并调用RegCreateKeyEx赋给新注册表键值的例子,用2.4.4.2 C++给新对象创建安全描述符。

      管理对象的系统组件或系统服务可以将对象特化的或默认的安全描述符保存下来永久化为对象的属性。如果对象的创建者没有设定一个安全描述符,那么系统将会使用继承的或者是一个默认的安全描述符,你可以用函数来修改一个对象安全描述符中的数据。

      目录服务对象,文件,目录,注册表键,以及桌面都是有父对象的安全对象。当你创建任何一个此类对象,系统就会检查父对象的安全描述符中可继承的ACEs。系统一般是将这些可继承的ACEs合并到新对象的安全描述符的ACLs中,你可以通过在安全描述符的控制位bit上设置SE_DACL_PROTECTED和SE_SACL_PROTECTED来避免继承ACEs的DACL和SACL。详情参见1.1.2.1.4.4  ACE的继承

 

1.1.2.1.2.2.1 新对象的DACL  DACL for a New Object

      系统使用下面的算法为大多数安全对象创建DACL:

  1. 对象的DACL是由对象的创建者指定的安全描述符的DACL。系统合并所有可继承的ACEs成为DACL,除非在安全描述符的控制位中设置了SE_DACL_PROTECTED控制位。
  2. 如果创建者没有指定一个安全描述符,系统会从继承的ACEs中构建一个DACL。
  3. 如果没有指定安全描述符、也没有可继承的ACEs,那么新对象的DACL就是主访问令牌或者是模拟访问令牌的创建者的默认DACL。
  4. 如果没有指定的、可继承的、默认的DACL,那么系统会创建一个没有DACL的对象,它允许所有用户访问这个对象。

系统使用不同的算法来创建新活动目录对象的DACL,更多信息参考如何设置新活动目录对象的安全描述符

 

1.1.2.1.2.2.2 新对象的SACL   SACL for a New Object

      对于大多数对象,系统使用下面的算法来创建SACL:

  1. 对象的创建者设置了安全描述符的SACL,除非安全描述符中的控制位bit设置了SE_SACL_PROTECTED标记,否则系统会合并所有可继承的ACEs到这个SACL中。即使设置了SE_SACL_PROTECTED标记,SYSTEM_RESOURCE_ATTRIBUTES_ACEs和SYSTEM_SCOPED_POLICY_ID_ACEs也会合并到新对象中。
  2. 如果对象的创建者没有设置安全描述符,系统会从可继承的ACEs中得到对象的SACL。
  3. 如果没有指定的安全描述符、也没有可继承的SACL,对象就没有SACL。

      要给新对象设置SACL,创建者必须有SE_SECURITY_NAME特权。如果为新对象创建的SACL仅包含一个SYSTEM_ATTRIBUTE_ACEs,那么SE_SECURITY_NAME特权就不是必需的了。如果对象的SCAL是从继承的ACEs中构建出来的,那么创建者也不需要有这个特权。

      系统使用一个不同的算法来创建活动目录对象的SACL,详情参考如何设置新活动目录对象的安全描述符

 

1.1.2.1.2.2.3 新对象的拥有者 Owner for a New Object

      对象的拥有者拥有该对象的WRITE_DAC访问权限,这意味可以修改对象的目录访问控制列表DACL,因此,也可以控制对象的访问权限。

      新对象的拥有者是来自创建进程的主访问令牌或者模拟访问令牌中的安全描述符的默认的拥有者。要获取/设置访问令牌中的默认拥有者,可以调用带TOKEN_OWNER结构的GetTokenInformation函数和SetTokenInformation函数,系统不允许你设置一个令牌的的默认拥有者到一个不可用的SID,比如说另一个用户账户的SID。

      一个有SE_TAKE_OWNERSHIP特权的进程可以设置自身为一个对象的拥有者。一个进程,若有SE_RESTOR_NAME特权或WRITE_OWNER对象访问权限,那么该进程可以设置一个对象的拥有者为任何可用的用户或组的SID。

 

1.1.2.1.2.2.4 新对象的主要用户组 Primary Group of a New Object

      一个新对象的主要用户组来源于对象创建者指定的安全描述符中的主要用户组。如果一个对象的创建者没有指定一个主要用户组,那么这个对象的主要用户组就是创建者的主要访问令牌或者模拟访问令牌的主要用户组。

 

1.1.2.1.2.3 安全描述符字符串 Security Descriptors Strings

      一个功能有效的安全描述符包含二进制格式的安全信息,Windows API提供了一些函数来让二进制安全信息和文本字符串之间进行转换。文本格式的安全描述符是不能使用的,但是它们在存储和传输安全描述符方面是有用的。

      调用ConvertSecurityDescriptorToStringSecurityDescriptor可以将安全描述符转化为文本格式。调用ConvertStringSecurityDescriptorToSecurityDescriptor可以将一个文本格式的安全描述符转换为一个功能有效的安全描述符。

      更多信息,参考安全描述符定义语言

 

1.1.2.1.3 访问控制列表 Access Control Lists

      访问控制列表ACL是一个访问控制项ACE的列表,ACL中的每一项ACE标识了一个受托者(用于ACE的用户账户、用户组账号或者一个登录会话)和指定是允许、拒绝、还是审核这个受托者的访问权限,一个安全对象的安全描述符可以包含两种ACLs:DACLs和SACLs。

      用户自定义的访问控制列表DACL标识了允许或者拒绝受托者对安全对象的访问。当一个进程访问一个安全对象的时候,系统会通过检查对象的DACL的ACE来决定是否赋予其访问权限。如果该对象没有DACL,系统就给所有用户赋予完全访问权限;如果这个对象的DACL没有ACEs,系统就拒绝所有对该对象的访问,因为DACL不允许任何类型的访问。系统将会按序检查ACEs,直到所有被请求的权限被允许,或者是任何一个请求的权限被拒绝。更多信息参考1.1.2.2 DACLs如何控制对一个对象的访问(实际是访问检查是如何工作的)。关于如何创建一个合适的DACL请参考创建一个DACL

      系统访问控制列表(SACL)允许系统管理员将对安全对象的访问记录在日志里。每一个ACE标识了一个特定的受托者的一种访问尝试,这个受托者会令系统生成一条该安全对象事件的日志记录,当一次访问尝试失败、成功或者二者都有的时候,SACL中的一个ACE会生成一条审核记录。关于SACL的详情,请参考 1.1.5 审核的生成和 1.1.2.1.5.4 SACL访问权限。

      不要尝试直接操作ACL,为了保证ACLs语义上的正确性,要使用合适的函数创建和操作ACL,详情参考 1.1.2.1.3.1 获取ACL信息 和 1.1.2.1.3.2 创建或者修改ACL。

      ACLs也提供对微软活动目录服务对象的访问控制,活动目录服务接口包含了创建和修改ACLs内容的常规操作。详情参考控制对活动目录对象的访问

 

1.1.2.1.3.1 获取ACL信息 Getting Information From an ACL

      有好多函数用来获得对访问控制列表ACL的访问控制信息,这些函数包括确定一个特定的受托者是否有ACL授权和审核的访问权限。其他函数可以抽取ACL中访问控制项ACEs中的信息。

      GetExplicitEnteriesFromAcl函数可以得到一个EXPLICIT_ACCESS数组,这个EXPLICIT_ACCESS结构记录了ACL中ACE的信息,这个在把一个ACL中的ACE信息拷贝到另一个ACL中时是很有用的。例如先用GetExplicitEnteriesFromAcl得到一个ACL中的ACE信息,然后将这个信息用SetEnteriesInAcl函数设置到一个新的ACL的ACEs中。

      GetEffectiveRightsFromAcl函数可以检查一个DACL是否赋予一个受托者的有效权限,受托者的一个有效的权限是DACL赋予一个受托者或者受托者所在的任何用户组的访问权限。这个函数可以检查指定DACL中所有允许和禁止访问的ACE项。

      用下列方法检查一个受托者是否有某个对象的访问权限:

  1. 调用GetSecurityInfo或者GetNamedSecurityInfo函数得到一个对象的DACL指针
  2. 调用GetEffectiveRightsFromAcl函数获得DACL赋予一个受托者的访问权限

      GetAuditedPermissionsFromAcl函数可以检查系统访问控制列表SACL,以得到一个受托者或受托者所在组是否拥有经过审核的访问权限。经过审核的访问权限说明了访问尝试的类型,这种访问引起系统在安全事件日志中生成一条审核记录。这个函数返回两个访问掩码,一个包含了监视过程中失败的访问请求权限,一个包含了监视过程中成功的访问请求的权限。GetAuditedPermissionsFromAcl检查ACL中所有系统审核级别的ACE。

 

1.1.2.1.3.2 创建或者修改ACL Createing or Modifying an ACL

      Windows提供了一组函数,用来创建ACL或者修改一个已存在ACL中的ACEs。

      SetEnteriesInAcl函数创建一个ACL,这个函数也可以给一个ACL设置一个组新的ACE,或者将一个或多个新的ACE和一个已存在的ACL的ACEs。SetEnteriesInAcl使用一组EXPLICIT_ACCESS结构来指定新的ACE组的信息,每一个EXPLICIT_ACCESS结构包含了一个ACE的描述信息。这个信息包含访问权限,ACE类型,控制ACE继承的标记,和一个标记受托者的TRUSTEE结构。

      为一个已经存在的ACL添加新的ACE:

  1. 使用GetSecurityInfo或者GetNamedSecurityInfo函数得到一个对象的安全描述符中的DACL或SACL。
  2. 为每一个新的ACE调用BuildExplicitAccessWithName函数,来为EXPLICIT_ACCESS结构填充上描述ACE的信息。
  3. 调用SetEnteriesInAcl,为新的ACE组指定一个已存在的ACL或者一个EXPLICIT_ACCESS结构数组,这个函数会创建并初始化这个ACL和ACE数组。
  4. 调用SetSecurityInfo或SetNamedSecurityInfo函数,把新的ACL赋给对象的安全描述符。

      如果调用者指定了一个已存在的ACL,SetEntriesInAcl会把新的ACE和这个ACL中已存在的ACEs的信息合并起来。考虑一下这种情况,比如有一个已存在的ACL赋予了对一个受托者的访问权限,而一个EXPLICIT_ACCESS结构拒绝对这个受托者的访问,这时SetEntriesInAcl函数为这个受托者添加一个新的拒绝访问ACE并删除或者是修改受托者的这个允许访问的权限。

      有一个例子演示了把一个新的ACE合并到一个已有的ACL,参见2.4.4.1 用C++修改对象的ACLs。

 

1.1.2.1.4 访问控制项 Access Control Entries

      访问控制项ACE是访问控制列表ACL中的元素,一个ACL中可以由0到多个ACEs。每一个ACE控制或者监视一个指定的受托者多一个对象的访问,关于添加、删除、修改一个对象的ACL中的ACEs,可参考2.4.4.1 用C++修改对象的ACLs。

      这里有六种类型的ACEs。所有的安全对象都支持这三种;其他三种是 1.1.2.1.4.2 对象专属的ACEs,只有目录服务对象支持。

      所有的ACE都包含下面的访问控制信息:

  • 一个安全身份SID,用来标识这个ACE用在哪个受托者上
  • 一个访问掩码,用来这个由ACE控制的访问权限
  • 一个标记,标识ACE的类型
  • 一组bit标记,用来决定子容器或者对象能否继承这个ACL附着的主对象的ACE。

      下面列出的ACE类型为所有安全对象所支持:

 

 

 

 

 

 

 

 

      参考 1.1.2.1.4.2 对象专属的ACEs,有一个对象专属的ACE列表。

      注:现在不支持系统警告对象的ACE。

 

1.1.2.1.4.1 受托者 Trustees

      受托者是指使用了访问控制项ACE的用户账户、用户组账户和登录会话。ACL中每一个ACE都有一个用来标识受托者的安全身份SID。

      用户账户包含真人用户的账户,或者类似用来登录本地计算机的Windows服务的账户。

      用户组账户不能用于登录一台计算机,但是他们对于用来拒绝或者允许一个或多个用户账户对一组权限的访问。

      登录SID标识了当前的登录会话,这个对于在登录期间允许或者是拒绝访问权限是非常有用的。

      访问控制函数使用TRUSTEE结构来标识一个受托者,TRUSTEE结构使用一个名字字符串或者一个SID来标识一个受托者。如果你使用了名字字符串的TRUSTEE结构来创建一个ACE,那么这些函数将会申请一个SID缓存,然后搜索和账户名对应的SID。这里有两个函数可以帮助你用一个名字字符串和一个SID初始化一个TRUSTEE:BuildTrusteeWithSid和BuildTrusteeWithName,这两个函数BuildTrusteeWithObjectAndSid和BuildTrusteeWithObjectAndName可以让你用对象专属的ACE初始化一个TRUSTEE结构,还有三个函数GetTrusteeForm、GetTrusteName和GetTrusteeName可以让你获得TRUSTEE结构的成员的值。

      TRUSTEE结构中的ptstrName成员可以是一个指向OBJECT_AND_NAME和OBJECT_AND_SID结构,这些结构指定了除了受托者对象名字和SID之外关于一个对象专属的ACE的信息。这可以让像SetEntriesInAcl和GetExplicitEntriesFromAcl这样的函数在存储特定对象的EXPLICIT_ACCESS中的Trustee成员的ACE的信息。

 

1.1.2.1.4.2 对象专属的ACEs Object-Specific ACEs

      对象专属的ACEs是为了支持目录服务对象的。一个对象专属的ACE包含了一对GUIDs,这个用来扩展ACE保护对象的方法。

 

 

 

 

 

 

      系统支持三种类型的对象专属的ACE类型。

      注:系统警告对象的ACEs目前不被支持。

 

 

 

 

 

 

 

 

      任何包含对象专属的ACE的ACL都必须有ACL_REVERSION_DS的权限。

 

1.1.2.1.4.3 DACL中ACEs的顺序 Order of ACEs in a DACL

      当一个进程访问一个安全对象的时候,系统会逐步遍历目录访问控制列表DACL中的控制入口ACEs,直至找到一个ACE允许或者拒绝这个请求的访问。根据出现在不同的DACL中的ACEs的不同顺序,一个DACL允许一个用户的访问权限有所不同。Windows XP为安全对象的ACL提供了一个首选的ACEs顺序,这个首选的ACEs顺序提供了一个简单的框架,它让一个禁止访问类型的ACE实际上也能拒绝访问。关于系统检查访问权限的算法,参考 1.1.2.2 访问检查是如何工作的。

      对于Windows Server 2003和Windows XP来说,这个合适的顺序被对象专属的ACE和自动继承的引入复杂化了。

      下面的步骤描述了这个首选顺序:

  1. 用户组中所有定义明确的ACEs位于可继承的ACEs前面
  2. 用户组中定义明确的ACEs中,禁止访问类型的ACEs位于允许访问的ACEs前面。
  3. 可继承的ACEs按照它们被继承的顺序存储。继承自子对象的父对象的ACEs放在最前面,接下来是继承自祖父对象的ACEs,接着向上沿着对象的继承树。
  4. 对每一个继承层次中的ACEs,禁止访问的ACEs位于允许访问的ACEs前面

      当然ACL中并非有所有的需要的ACE类型。

      比如AddAccessAllowdAceEx和AddAccessAllowedObjectAce在ACL末尾添加一个ACE。确保ACEs以合适的顺序添加到ACL中是函数调用者的责任。

 

1.1.2.1.4.4 ACE的继承 ACE Inheritance

      一个对象的ACL可以包含了继承自它的父对象容器的ACEs,例如,一个注册表子键可以继承来自注册表上层结构的键的ACEs。类似地,在NTFS系统上的文件继承包含它的文件夹的ACEs。

      一个ACE的ACE_HEADER结构包含一组继承标记,这组标记控制了ACE的继承和以及附加在这个对象上的ACE的效果。系统会解释这个继承标记,还有其他根据ACE继承顺序的继承信息。

      下面这些规则可以用下列特性加强:

  • 对可继承ACEs的自动传播的支持
  • 区别继承的ACEs和直接设置到对象的ACEs之间的不同的标记
  • 允许你指定子对象类型的对象专属的ACEs,这种子对象可以继承ACE
  • 通过设置安全描述符的控制位bit为SE_DACL_PROTECTED或者SE_SACL_PROTECTED,不设置SYSTEM_RESOURCE_ATTRIBUTE_ACE和SYSTEM_SCOPED_POLICY_ID_ACE,来阻止DACL、SACL继承ACEs。

1.1.2.1.4.5 可继承ACEs的自动传播 Automatic Propagation of Inheritable ACEs

      SetNamedSecurityInfo和SetSecurityInfo支持可继承的ACEs的自动传播,例如,如果你使用这两个函数为NTFS系统的一个目录添加一个可继承ACE,系统会把这个ACE应用到对应的子目录和文件的ACL中。

      直接设置到对象的ACE比继承的ACE拥有更高的优先级,系统为了实现这种优先级别,把DACL中直接设置到对象的ACE放置于可继承的ACEs前面,当你调用SetNamedSecurityInfo和SetSecurityInfo函数设置一个对象的安全信息的时候,系统会强制把当前的继承模型应用到目标对象层次结构下的所有对象。那些转换到当前继承模型下的对象,其SE_DACL_AUTO_INHERITED和SE_SACL_AUTO_INHERITED位都被设置为目标对象的安全描述符的控制域。

      当你创建一个反映当前继承模型的安全描述符的时候,注意不要改变安全描述符的语意。比如,允许或者拒绝ACEs永远不能在彼此之间移动。如果需要做此类动作(比如说把不可继承的ACEs放置于ACL前面),ACL要标记为被保护状态避免语意的改变。

      当系统传播可继承ACEs到子对象时使用一下规则:

  • 当一个没有DACL的子对象继承了ACE时,该子对象的DACL只能包含可继承的ACE。
  • 当一个含有空DACL的子对象继承ACE时,该子对象的DACL也是只能包含可继承的ACE。
  • 当你从一个父对象中移除一个可继承的ACE时,自动继承机制会移除所有子对象中继承的ACE的副本。
  • 如果自动继承机制导致移除了子对象的DACL中所有ACE的时候,子对象将会拥有一个空的DACL,而不是没有DACL。

      使用这些规则把一个没有DACL的对象转化为拥有一个空DACL的对象的时候,会导致意想不到的错误。系统允许没有DACL的对象拥有所有访问权限,但是一个拥有空DACL的对象没有任何访问权限。下面举例说明这些规则如何创建一个空DACL,假设你要给一个树形对象组的根对象添加一个可继承的ACE,自动继承机制会传递该ACE到树结构中所有的子对象中,一开始没有DACL的子对象,现在有了一个包含单个可继承ACE的DACL。如果你现在又把这个可继承的ACE从根对象中移除,系统会自动地把这个改变传递到子对象中,那么一开始没有DACL的子对象(拥有所有访问权限)现在拥有一个空DACL(没有任何访问权限)。

      为了保护没有DACL的子对象不受可继承ACEs的影响,要给该对象的安全描述符中设置SE_DACL_PROTECTED标记。

      关于如何恰当地创建DACL的信息,请参考创建一个DACL

 

1.1.2.1.4.6 ACE继承规则 ACE Inheritance Rules

      系统把可继承的ACEs传播到子对象,会依据一组继承规则。系统根据1.1.2.1.4.3DACLs中ACE的顺序把可继承的ACEs放入DACL中。系统在所有的可继承ACEs中设置INHERITED_ACE标记。

      容器子对象和非容器子对象继承ACEs是有区别的,这要看继承标记的组合情况而定。这些继承规则对DACLs和SACLs都是一样的。

      

 

 

 

 

 

 

 

 

 

 

 

      如果一个继承的ACE对子对象是有效的,系统会为子对象把所有通用权限映射到特定权限。类似地,系统会把例如CREATOR_OWNER这样的通用安全身份SID映射到适当的SID,如果一个继承来的ACE是一个仅被继承的ACE,所有的通用权限和通用SID都不变,以便在映射的时候这些ACE在下一代子对象被正确地继承。

      对于容器对象继承一个ACE的情况,该容器对象将得到一个有效的ACE,并且其后代对象也可以继承该ACE,容器对象可能继承两个ACE。这种情况在可继承的ACE包含通用信息的时候就会发生。容器继承一个仅可被继承的ACE,该ACE中包含了通用信息和一个仅在通用信息被映射的时候才有效的ACE。

      一个对象专属的ACE有一个InheritedObjectType成员,它可以包含一个GUID来标识一个可以继承ACE的对象的类型。

      如果没有指定InheritedObjectType GUID,对象专属的ACE的继承规则和标准ACE是相同的。

      如果指定了InheritedObjectType GUID,那么如果设置了OBJECT_INHERIT_ACE标记,匹配该GUID的对象可以继承该ACE;如果设置了CONTAINER_INHERIT_ACE标记,匹配该GUID的容器也可以继承该ACE。注意,当前仅有DS对象支持对象专属的ACE,并且DS(Directory Service)对象把所有对象类型都视看作容器。

 

1.1.2.1.4.7 对象属性控制访问的ACEs ACEs to Control Access to an Object's Properties

      目录服务对象的DACL可以包含一个ACEs层次结构,如下所述:

  1. 保护对象的ACEs
  2. 保护对象指定属性集的对象专属的ACEs
  3. 保护对象指定属性的对象专属的ACEs

      在这个层次结构中,权限可以在更高层次上赋予和拒绝,也可以在更低层次上。例如,一个属性集中的一个对象专属的ACE允许一个受托者拥有ADS_RIGHT_DS_READ_PROP权限,受托者隐式地有了读取那个属性集中所有属性的访问权。类似地,允许ADS_RIGHT_DS_READ_PROP访问的对象中的一个ACE会赋予受托者对该对象所有属性的读取访问权。

      下图示意了一个假设的DS对象的和它的属性集。

 

      

 

      假设你想要获得下以下对DS对象属性的访问权:

  • 组A对该DS对象所有属性进行读/写
  • 其他对象(除组A之外)对除属性D之外的属性进行读写

      为此,可按照下表对对象的DACL中的ACEs进行设置。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      组A的ACE没有对象GUID,这意味着它有对所有对象属性的访问权,属性集1的对象专属ACE可让组A获得属性A和属性B所有访问权。其他对象专属ACE可让组A获得属性C的所有访问权。注意,虽然这个DACL没有任何拒绝访问的ACE,但是它隐式地拒绝了除组A之外的对象对属性D的访问。

      当一个用户尝试访问对象的属性,系统会按一定顺序检查该对象的ACEs,直到请求的访问被明确地接受、拒绝,或者没有ACEs(也就是说该访问被隐式地拒绝)。

      系统的算法是:

  • 应用到该对象的ACEs
  • 应用到包含要被访问属性的属性集的对象专属ACEs
  • 应用到将要被访问的属性的对象专属ACEs

      系统忽略应用到其他属性集和属性的对象专属ACEs。

 

1.1.2.1.5 访问权限和访问掩码 Access Rights and Access Masks

      所谓访问权是一个位标记,它对应于一组特殊的操作,这个操作是一个线程可能对一个安全对象做的操作。比如,一个注册表键有一个KEY_SET_VALUE访问权,这对应于一个线程可以对这个键设置值。如果一个线程要对一个对象进行操作,但是没有必要的操作权限,系统就不会执行该操作。

      所谓访问掩码是一个32位的值,每一位对应于对象支持的访问权。所有Windows安全对象都使用一个包含下列类型访问权的位:

  • 通用访问权 (1.1.2.1.5.2)
  • 标准访问权 (1.1.2.1.5.3)
  • SACL访问权 (1.1.2.1.5.4)
  • 目录服务访问权 (1.1.2.1.5.5)

      当一个线程尝试打开一个对象的句柄时,线程通常会指定一个访问掩码以请求一组访问权。比如一个应用程序需要设置和查询注册表的键,则可以使用请求KEY_SET_VALUE和KEY_QUERY_VALUE访问权的访问掩码打开该键。

      下表给出了操作各种安全对象的安全信息的函数:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1.2.1.5.1 访问控制掩码格式 Access Mask Format

      所有安全对象使用访问掩码来整理访问权,如下表所示:

 

      

 

      在这个格式中,低16位是对象专属访问权,接着的8位是标准访问权(使用的对象类型最多),高4位用来标识通用访问权(每种对象可以映射到一组标准和对象专属权限)。ACCESS_SYSTEM_SECURITY位对应于访问对象的SACL的权限。

      

1.1.2.1.5.2 通用访问权限 Generic Access Rights

      安全对象使用的访问掩码格式中高4位指定了通用访问权限。每种类型的安全对象会映射这些位到一组自身的标准访问权限以及对象专属的访问权,比如,一个Windows文件对象的GENERIC_READ位会映射到标准访问权限READ_CONTROL和SYNCHRONIZE,以及对象专属访问权FILE_READ_DATA、FILE_READ_EA和FILE_READ_ATTRIBUTE。其他类型对象会把GENERIC_READ位映射到那种类型对象适当的访问权。

      你可以使用通用访问权指定你想打开一个对象的句柄时需要的访问类型。这比专门指定对应的标准的和对象专属访问权要简单得多。

      下表给出了为通用访问权定义的常量:

 

 

 

 

 

 

 

 

 

 

 

 

      定义了私有安全对象的应用程序同样使用通用访问权限。

 

1.1.2.1.5.3 标准访问权限 Standard Access Rights

      每种安全对象都有一组对应于对象特有操作的访问权。对于对象专属的访问权,还有一组对应于所有安全对象标准访问权。

      访问掩码格式包含了一组bit位来标识标准访问权。在winnt.h中有下列为标准访问权定义的Windows常量:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      winnt.h中还定义了下面的标准访问权限组合的常量:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1.2.1.5.4 SACL访问权限 SACL Access Right

      访问权ACCESS_SYSTEM_SECURITY标记控制获取和设置一个对象中安全描述符的SACL的资格。仅当请求线程中访问令牌中有SE_SECURITY_NAME特权,系统才会赋予这些访问权。

      为了访问对象的SACL:

  1. 调用AdjustTokenPrivilege函数,得到SE_SECURITY_NAME特权
  2. 当你打开一个对象的时候,请求ACCESS_SYSTEM_SECURITY访问权
  3. 使用诸如GetSecurityInfo或SetSecurityInfo函数获得或设置对象的SACL
  4. 调用AdjustTokenPrivilege函数,禁用SE_SYSTEM_SECURITY特权

      用GetNamedSecurityInfo或SetNamedSecurityInfo函数访问SACL启用SE_SECURITY_NAME标记。这个函数间接地请求访问权。

      DACL中的ACCESS_SYSTEM_SECURITY访问权不可用,因为DACLs不能控制对SACL的访问权。但是,你可以在一个SACL中使用ACCESS_SYSTEM_SECURITY访问权来审核使用访问权的尝试。

 

1.1.2.1.5.5 目录服务访问权限 Directory Services Access Rights

      每一个活动目录对象都有一个被赋予的安全描述符。为受托者指定一组权限可以设置在这些安全描述符中。这些权限列在下表中,详细信息参考控制访问权

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1.2.1.5.6 向一个对象的请求访问权限 Requesting Access Rights to an Object

      当你打卡一个对象句柄,返回的句柄含有一些访问权限的组合,有些函数(比如说CreateSemaphore)并不会要求指定一组的需要的访问权,这些函数通常会尝试为得到全部访问权而打开句柄。其它函数(比如CreateFile、OpenProcess)会让你指定一组你想要的访问权。你应该仅指定你需要的权限,而不是为了得到全部访问权而打开一个句柄。如果对象的DACL仅支持有限的访问权,这会阻止你用一种意想不到的方法是用句柄,同时增大成功请求的机率。

      打开一个对象的句柄时,使用通用访问权指定必要的访问权。这通常比指定标准访问权和对象专属访问权要简单。另外,使用MAXIMUM_ALLOWED常量来得到被打开的对象的对调用者来说全部有效权限。

      注意: MAXIMUM_ALLOWED不能用于ACE。

      打开一个对象的句柄时,要求有ACCESS_SYSTEM_SECURITY访问权,来得到或者设置对象安全描述符中的SACL。

 

1.1.2.1.6 统一授权策略 Centralized Authorization Policy

      动态访问控制(DAC)方案可以帮助扶着企业文件服务的统一访问控制管理员。多数组织有多个想要进行访问控制的区域。

      例如:

  • 对敏感信息的控制,其中标记为敏感的文件有特殊的许可。
  • 对隐私信息的文件访问控制。
  • 对基于组织保留政策的文档要限制访问权限。

      有许多新的授权政策概念允许管理员来统一定义这些政策,通过允许定义和维护(但是单独使用)这些访问请求作为一个政策,并简化定义流程。

      Windows8中有两个新的活动目录政策对象,一个是统一授权政策(CAP),一个是统一授权政策规则(CAPR),这两个对象是基于需求和资源的属性的表达。具体使用时,管理员把CAPR定义为特定的授权政策,这些政策可以应用到具有特定属性或者满足一定应用条件的资源中。比如标记为“高商业影响”的文档,在一个可表达的组织中或者一个要使用政策的可标识资源中,用Windows 8 DAC的方式,CAPEs可能定义为每一个想要的访问控制政策。一个CAP是一个可一起应用到资源的CAPRs集合,下图显示了CAP和CAPEs的关系,以及在定义和使用这些对象到文件资源中的概念性步骤。

 

      

 

1.1.2.1.6.1 统一授权策略 Central Authorization Policies

      统一授权策略(CAP)把一组特定的CAPRs集合在一起成为一个授权策略。把特定的CAPRs组合为一个组织的整体性的策略,CAPRs可以引用在一起,并应用于一组资源。可以通过引用的方式把多个集合到一个CAP中。一旦定义好一个CAP之后,就可以用资源管理器把它部署到组织授权策略的资源上。

      一个CAP有以下属性:

  • 一个CAPR的集合,一个CAPR对象的引用列表
  • 一个身份SID
  • 描述
  • 名字

      一个CAP在对由管理员允许的文件和文件夹访问审核的时候进行计算。在一个AccessCheck调用中,一个CAP审查逻辑上由任意的ACL审查组成,这意味着为了访问一个应用了CAP的文件,用户需要同时根据CAP策略(内含的CAPRs)和应用在文件上的ACL规则来审查。

      CAP例子:

 

      CAP定义:

      可以用ADAC中的一个UX在活动目录中创建和修改一个CAP。这个ADAC要允许管理员创建一个CAP并指定一组构建CAP的CAPRs。

 

另外

 

1.1.2.1.6.2 统一授权策略规则 Central Authorization Policy Rule

      统一授权规则CAPR的目的是为了提供一个域名范围的、关于组织授权策略的独立定义。管理员可以通过定义CAPR类加强某些授权需求。因为CAPR定义的仅是某一个方面的授权策略需求,如果所有这些组织授权策略需求编写为一个单独的策略定义,它还可以更加简单易懂。

      CAPR还有下列属性:

  • 名字 - 对管理员区分CAPR的身份
  • 描述 - 定义CAPR的目的,客户需要的关于CAPR的任何说明
  • 适用性说明 - 定义在那种资源或情形下可以使用该策略
  • ID - 审核CAPR修改时的身份
  • 有效访问控制策略 - 一个Windows安全描述符
  • 异常表述 - 一个或多个表达式,该表达式提供了改写策略并根据表达式计算结果授权访问一个对象的方法
  • 阶段性策略 - 一个可选的Windows安全描述符,包含一个定义了建议性授权策略的DACL,该策略是独立于有效策略进行测试但是不强制的。如果在有效策略和该策略之间有任何差别,这些差别将会被记录在审查时间日志中。
  • 因为阶段性的审查可能会对系统性能有意想不到的效果,组策略管理员必须可以选择指定的可以使用该策略的机器。这使得阶段性审查发生在这些机器的一个子集的时候,已有的策略在大多数OU机器上是适当的,
  • P2 - 一些机器上的本地管理员应该拥有禁用阶段性审查,如果那些机器上的阶段性审查造成了过多的性能降级。
  • CAP的反向链接 - 一个反向链接到该CAPs的反向链接列表,该CAP可能被引用到CAPR

      在访问审查中,系统根据适用性表达式计算适当的CAPR。如果一个CAPR是适用的,系统就会计算是否可以为请求的用户提供指定的资源。这个CAPE计算结果逻辑上是相关资源DACL的结果与任何其他适当的有效CAPRs的交集(AND计算)。

      CAPRs的例子:

 

      CAPEs中否定ACEs

      在Windows 8中,将不支持在ACPRs中否定ACEs,CAPR授权UX将不支持创建一个否定ACE。另外,当LSA从活动目录的时候检索CAP,LSA将会检查没有包含否定ACE的CAPR。如果发现一个CAPR中含有否定ACE,那么这个ACPR将被视为无效,并且不会拷贝到注册表或者SRM中。

      注意,如果没有发现ACE,将不会强制进行访问审查。这时候会使用CAPR中的否定ACE。正如所料,授权工具将会阻止这个发生。

      CAPE定义

      活动目录管理中心(ADAC)的一个新UX创建CAPR。ADAC中,创建CAPR会有一个新的任务选项,选择任务的时候,ADAC会用一个弹出框提示用户,并询问用户对CAPR的名字和描述。当用户提供这些之后,任何已有的CAPR元素的控制定义也将生效。对于每一个已有的CAPR元素,UX将会调出ACL-UI来允许表达式和/或ACLs的定义。

      相关主题

      AccessCheck函数

      动态访问控制情景

 

1.1.2.1.7 安全身份 Security Identifiers

      一个安全身份(SID)是一个用来识别受托者的独特的变长值。每一个账号都有一个独特的SID,由另一个权威账户赋予,比如说Windows域管理者,并存储在安全数据库中。每次用户登录的时候,系统就为用户从安全数据库中取出这个SID,并把它放置在这个用户的访问令牌中。在随后与系统的交互中,系统使用访问令牌中的这个SID来区分用户。当一个SID用来作为一个用户或组的唯一身份的时候,是不能用来标识另一个用户或组身份的。

      Windows安全在一下安全元素中使用SID:

  • 在安全描述符中,用来标识一个对象或者主要组的所有者
  • 在访问控制项ACE中,为受托者标识哪一个访问是允许的,拒绝的,或者审查的
  • 在访问令牌中,标识一个用户属于哪一个用户或组

      另外,对于为用户或组特别创建的、域范围内的SID,有一些公开的SID用来标识通用组和用户。例如这个SID,Everyone and World,标识了所有用户。

      大多数应用程序是不需要用到SID的。因为这些公开的SID的名字彼此不同,你应该使用函数从预定义的常量上创建SID,而不是使用这些公开SID的名字。例如,美国英语版本的Windows操作系统中有一个命名为"BUILTIN\Administrator"公开的SID,可能在不同的国际系统版本中有不同的名字。创建公开SID的例子,可以参考 用C++在一个访问令牌中搜索一个SID。

      如果你真的需要使用SID,不要直接操作它们,应该使用下列函数。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1.2.1.7.1 SID的结构 SID Component

      一个SID值包含提供了SID结构信息的部分,和唯一标识了受托者的部分。一个SID包含下列部分:

  • 一个SID结构的修订级别
  • 一个48bit的标识符权限,用来标识赋予该SID的权限
  • 若干数量的子权限或相对标识符(RID)值,该RID值唯一地标识了相关的赋予了SID权限的受托者。

      标识符权限值和和子权限值的组合保证了没有两个SID会相同,即使两个不同的SID分配权威分配了相同的RID值的组合。一个SID分配权威分配一个特定RID,仅一次。

      SID以二进制的方式存储于一个SID结构中。为了演示一个SID,你可以调用ConvertSidToStringSid函数来把一个二进制的SID转为字符串格式。可以调用ConvertStringSidToSid函数,把转换一个SID字符串格式到有效的、可用的SID。

      这些函数使用下列SID标准字符串符号,这使得它们的结构可视化变得更简单:

S-R-I-S...

      在这个符号中,字符S表示数字序列是一个SID,R表示修订级别,I是标识符权限值,S...是一个或多个子权限值。

      下面的例子 使用这个格式演示了本地管理员组的公开相对域SID:

S-1-5-32-544

      在这个例子中,SID有下列组成部分,括号中的常量是定义在Winnt.h中公开的标识符权限和RID值。

  • 修订级别为1
  • 标示符权限值为5(SECURITY_NT_AUTHORITY)
  • 第一个子权限是32(SECURITY_BUILTIN_RID)
  • 第二个子权限是544(DOMAIN_ALIAS_RID_ADMINS)

 

1.1.2.1.7.2 公开的SIDs Well-Known SIDs

      公开的安全描述符(SID)定义了通用组、用户。比如区分下列组合用户的公开SID:

  • Everyone or World, 包含所有用户的组
  • CREATOR_OWNER,在可继承ACE中用作一个占位符。当一个ACE是继承来的,系统就把该SID替换为创建对象的SID
  • 本地计算机上内置域的管理员组

      还有些国际通用的SID,可用于所有基于这个安全模型的安全系统上,甚至是非Windows系统。另外,还有一些公开的SID仅能用于Windows系统。

      Windows API为公开标识符权限和相关标示符(RID)值定义了一组常量。你可以用这些常量来创建公开的SID。下面的例子组合了SECURITY_WORLD_SID_AUTHORITY和SECURITY_WORLD_RID来演示为所有用户使用的国际通用SID。

S-1-1-0

      这里例子使用SID字符串符号,其中S网i标识SID的字符串,第一个1是SID的修订级别,剩余的两个数字是SECURITY_WORLD_SID_AUTHORITY和SECURITY_WORLD_RID常量。

      你可以使用AllcateAndInitializeSid函数,结合标识符权限值和多大8个子权限值的组合,来创建一个SID。例如,确定一个登录用户是否是一个公开组的成员,使用AllocateAndInitializeSid函数来为公开组创建一个SID,使用EqualSid函数来比较该SID和用户访问令牌中的组SID。要看参考示例的话,请看 用C++在访问令牌中搜索一个SID。你必须使用FreeSid函数来释放由AllocatedAndinitializeSid函数申请的SID。

      本节剩余部分包含了公开SID的表格,标识符权限表格和子权限常量表格,你可用它们来创建SID。

      下面是部分国际通用SID:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      下表列出了预定义的标识符权限常量。前4个值用于国际通用SID,最后一个用于Windows公开SID中。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      下列RID值和国际通用SID一起使用。标识符权限列展示了标识符权限的前缀,使用这个你可以和RID组合来创建国际通用SID。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      SECURITY_NT_AUTHORITY(S-1-5)预定义了标识符权限生成SID,这些SID不是国际通用SID,仅在Windows安装上有意义。你可以使用下列RID值和SECURITY_NT_AUTHORITY来创建公开SID。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      下面域相关的RID:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      以下RID用于指定受托者诚信水平:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      下表是你可以用来为本地组(别名)构造公开SID的域相关的RID。关于本地组合全局组的详细信息请参考本地组函数组函数

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      枚举值WELL_KNOWN_SID_TYPE定义了一个常用的SID的列表。另外,安全描述符定义语言(SDDL)使用SID字符串来引用有某种字符格式的公开SID。

 

1.1.2.2 访问检查是如何工作的 How Access Check Works

      当一个线程尝试访问安全对象的时候,系统会允许或拒绝该访问。如果一个该对象没有DACL,那么系统会允许该访问;反之,系统会搜索线程中使用的对象的DACL中的ACE。对象的DACL中的每一个ACE都指定了访问权限允许或拒绝一个受托者对象,这个受托者可能是一个用户账号,一个组账号,或者一个登录会话

      DACLs

      系统会比较每个ACE中的受托者和线程访问令牌中指定的受托者。一个访问令牌包含一个安全描述符,指定用户属于哪个一个用户账号或组账号。一个访问令牌也包含一个登录ID用来标识当前登录会话。在一个访问审查中,系统忽略未激活的组安全描述符(SID)。关于激活、取消、以及仅限拒绝的SID,参考 访问令牌中的SID属性。

      一般地说,系统使用请求访问线程的第一访问令牌。但是如果一个线程模拟令一个用户,系统使用线程的模拟令牌。

      系统检查按序检查每一个ACE,直到下列事件中的某一个发生:

  • 一个访问拒绝(Access-denied)ACE明确否定列在线程访问令牌中的受托者请求的任何访问权限。
  • 一个或多个列在线程访问令牌中的受托者的允许访问(access-allowed)ACE明确地允许所有访问权限。
  • 所有ACE都经过了审查,但是还有至少一个请求的访问权限没有被明确地允许,这种情况下,访问隐式地被拒绝。

      下图展示了一个对象的DACL是如何允许一个线程,而拒绝另一个线程的。

 

 

      对于线程A,系统读到ACE 1就立即拒绝了访问,因为该线程访问令牌中的用户位于访问拒绝ACE 1中。这种情况下系统不会检查ACE 2和3。对于线程B,ACE 1没有使用到,所以系统直接处理ACE 2, ACE 2允许写访问,而ACE 3允许读和执行权限。

      因为当请求的访问明确地被允许或拒绝时,系统会停止审查ACE,所以DACL中的ACE的顺序是很重要的。注意如果在例子中ACE的顺序是不同的话,系统是可能会赋予线程A的访问。对于系统对象,操作系统定义了优先选择的DACL中的ACE顺序

 

1.1.2.3 线程和安全对象之间的交互 Interaction between Threads and Securable Objects

      当一个线程尝试访问一个安全对象时,系统会在允许线程执行之前执行访问审查操作。在访问审查中,系统会对线程访问令牌中的安全信息和该对象安全描述符中的安全信息作比较。

  • 访问令牌包含一个安全描述符(SID),其定义了与线程相关的用户。
  • 安全描述符定义了一个对象的拥有者,包含了一个用户自定义访问控制列表(DACL)。这个DACL包含了一组访问控制项(ACEs)每一个ACE指定了允许或拒绝特定用户或组的访问权限。

      系统检查对象的DACL,会搜索来自线程访问令牌、同时又定义了用户或组SID的ACE。系统会检查每一个ACE,直到访问被允许或拒绝,或者没有ACE。不难想象,一个访问列表ACL可以拥有多个用于访问令牌SID的ACE。若此,每个ACE赋予的访问权限就会累积。例如,如果一个ACE赋予了一个组的读权限,同时另一个ACE赋予了该组中一个用户以写权限,那么这个用户可以同时拥有读和写对象的权限。

 

 

1.1.2.4 DACLs和ACEs DACLs and ACEs

      如果一个Windows对象没有自定义访问控制列表(DACL),系统就会赋予其全部访问权。如果对象拥有一个DACL,系统仅在其DACL中的某个ACE明确允许该访问时方可访问。如果该DACL中没有ACE,系统不允许访问任何对象。类似地,如果一个DACL有一组ACE,允许一个受限的用户和组,系统隐式地拒绝不在ACE中的所有受托者的访问。

      大多数时候,你可以使用允许访问ACE来控制对一个对象的访问,你不需要明确地拒绝对某个对象的访问。例外的情况是,当一个ACE允许一个组的访问请求,但是你想要拒绝该组中的某个用户。为此,在该用户的DACL中对这个组的所有允许访问ACE之前放置一个访问拒绝ACE。注意ACE的顺序是很重要的,因为系统会按序读取ACE直到访问被允许或被拒绝。用户的访问拒绝ACE必须出现在前面,否则,系统会读到组的允许访问ACE,这会赋予受限制的用户的访问权。

      下图展示了一个DACL拒绝一个用户的访问,但是允许赋予另外两个组访问权。组A中的用户通过累积被允许的组A的权限和所有用户的权限而得到了读、写、执行访问权限。例外是Andrew,他被访问拒绝ACE拒绝,尽管他属于所有用户组的一员。

 

 

1.1.2.5 空的DACLs和DACLs为空 Null DACLs and Empty DACLs

      如果一个对象的安全描述符的DACL被设置为NULL,那么一个null DACL就被创建了。一个null DACL赋予所有请求它的用户以所有权限,普通的安全检查就不会执行了。一个null DACL不能和一个空DACL混淆。一个空DACL是一个被正确地创建和初始化的DACL,它不包含ACE。一个空DACL不会赋予所属对象任何权限。

      关于如何创建一个DACL的例子,参考创建DACL

 

1.1.2.6 允许匿名访问 Allowing Anonymous Access

      默认的安全策略限制匿名本地访问拥有任何权限。管理员可以根据情况添加或删除权限。

      一个本地访问组可以像所有用户的访问权限一样。管理员可以适当地增减那个组的用户数量,这个组名就是Pre-Windows 2000-Compatible Access Group。

      更多详情,参考本地组函数主题表中函数参考页。

 

1.1.3 安全描述符定义语言 Security Descriptor Definition Language 

      安全描述符定义语言(SDDL)定义了字符串格式,函数ConvertSecurityDescriptorToStringSecurityDescripto和ConvertStringSecurityDescriptor使用该格式来把一个安全描述符SID描述为一个文本字符串。该字符串还定义了描述安全描述符中组成部分的信息的字符串元素。

      注意 有条件的ACE有不同的SDDL格式,这一点不同于其他ACE类型。对于ACE的详情,参考ACE字符串。对于有条件的ACE,参考条件ACE的安全描述符定义语言。

 

相关主题

安全描述符字符串格式

条件ACE的安全描述符定义语言

ACE字符串

SID字符串

[MS-DTYP]:安全描述符定义语言

 

1.1.3.1 安全描述符字符格式 Security Descriptor String Format

      安全描述符字符串格式是安全描述符中存储或交换信息的一种文本格式,函数ConvertSecurityDescriptorToStringSecurityDescripto和ConvertStringSecurityDescriptor使用了改格式。

      格式是带有标识安全描述符四个主要组件的null终止字符串:拥有者(O:),主要用户组(G:),DACL(D:),和SACL(S:)。

      注意:ACE和条件ACE有不同的格式,对于ACE的详情,参考ACE字符串。对于有条件的ACE,参考条件ACE的安全描述符定义语言。

 

 

 

      owner_sid

            定义了对象的拥有者的SID字符串。

      group_sid

            定义了对象的主要用户组的字符串

      dacl_flags

            DACL用到的安全描述符控制标记。关于这些控制标记的详细介绍,请参考SetSecurityDescriptorControl函数。dacl_flags可以是下列字符串中的零个或多个级联:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      sacl_flags

            SACL用到的安全描述符控制标记。sacl_flags字符串用到的控制位字符串和dacl_falgs相同。

      string_ace

            描述安全描述符中DACL和SACL的ACE的字符串。关于ACE字符串格式的详情,请参考1.1.3.3 ACE字符串。每一个ACE字符串都用圆括号括起来了。

      不需要的部分可能会从安全描述符字符串中省略。例如SE_DACL_PRESENT标记不会设置到输入安全描述符中,输出字符串ConvertSecurityDescriptorToStringSecurityDescriptor不会包含D:部分。你仍然可以使用SECURITY_INFORMATION位标记来指示组成部分来包含一个安全描述符字符串。

      安全描述符字符串格式不支持NULL ACL。

      为了表示空ACL,安全描述符字符串包含D:或者S:标记,但是没有任何其他的字符串信息。

      安全描述符字符串会以不同的方式存储SECURITY_DESCRIPTOR_CONTROL位。在字符串中SE_DACL_PRESENT和SE_SACL_PRESENT位使用D:和S:来标记。DACL和SACL中使用的其他位存储在dacl_flags和sacl_flags中。SE_OWNER_DEFAULTED、SE_GROUP_DEFAULTED、SE_DACL_DEFAULTED和SE_SACL_DEFUALTED位不会在安全描述符中存储。SE_SELF_RELATIVE位不会存储在字符串中,但是ConvertStringSecurityDescriptorToSecurityDescriptor总是会设置到输出安全描述符中。

      下面的例子展示了相关的安全描述符中安全描述符字符串和信息。

      字符串1:

 

      安全描述符1:

 

 

      字符串2:

 

 

      安全描述符2:

 

 

      相关主题

      1.1.3.3 ACE字符串

      1.1.3.2 条件ACE的安全描述符定义语言

 

1.1.3.2 条件ACE的安全描述定义语言 Security Descriptor Definition Language  for Conditional ACEs

      当执行访问审查时条件访问控制项(ACE)允许一个访问条件执行计算。安全描述符定义语言SDDL提供了一种定义条件ACE的字符串语法。

      条件ACE的SDDL和所有ACE都一样,只是语法上是在ACE字符串的末尾加上了条件声明。更多关于SDDL信息参考安全描述符定义语言

      在资源属性中“#”符号和“0”是同义词。例如, D:AI(XA;OICI;FA;;;WD;(OctetStringType==#1#2#3##))等同于(并解释为)D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300)).

  • 条件ACE字符串格式
  • 条件表达式
  • 属性
  • 操作符
  • 操作符优先级
  • 未知数值
  • 条件ACE计算
  • 示例
  • 相关主题

      条件ACE字符串格式

      安全描述符中的每个ACE都用圆括号包围起来。下面是按序排列,并用分号分割的ACE的域。

AceType;AceFlags;Rights;ObjectGuid;InheritObjectGuid;AccountSid;(ConditionalExpression)

      在ACE字符串中描述的域,有下面的例外。

  •       AceType域可以是下面字符串的其中之一:

 

 

 

 

 

 

 

 

 

 

  • ACE字符串包含一个或多个条件表达式,在每个字符串的结尾使用圆括号包围起来。

      条件表达式

      一个条件表达式可以包含下列元素中的任何一个。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      属性

      在客户端上下文中,一个属性表示AUTHZ_SECURITY_ATTRIBUTES_INFOMATION中的一个元素。一个属性名可以包含任何字母数字和符号":", "/", ".", 和 "_"。

      一个属性值可以由下列值:

 

 

 

 

 

 

 

 

 

 

 

 

      操作符

      下面定义的操作符是在条件表达式中测试属性值的。所有这些都是二元操作符,并以AttributeName Operator Value的形式。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      另外,对于一元操作符,Member_Of、和取反操作符(!),正如条件表达式表中所描述的。

      “Contains”操作符必须执行并且后面跟一个空白符,“Any_of”操作符后面必须跟一个空白符。

      操作符优先级

      操作符按照下面的优先级顺序,相同优先级的按照从左向右的顺序进行计算。

  1. Exists, Member_of
  2. Contains, Any_of
  3. ==, !=, <, <=, >, >=
  4. !
  5. &&
  6. ||

      另外,一个条件表达式的任何部分都可以用圆括号包围起来。带圆括号的表达式首先计算。

      未知值

      有时候条件表达式的结果返回一个Unknown。例如,当指定的属性不存在的时候,任何关系操作符都返回Unknown。

      下表中描述了两个条件表达式之间进行逻辑与(AND)计算的结果,ConditionalExpression1 and ConditionalExpression2.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      下表中描述了两个条件表达式进行逻辑或(OR)操作符计算的结果,ConditionalExpression1 orConditionalExpression2.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      

      Unknown条件表达式的否定操作还是Unknown。

 

      条件ACE计算

      下表描述了根据条件表达式最终计算结果的条件ACE结果的访问审查。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      示例

      下面的例子显示了使用SDDL定义的条件ACE如何代表指定的访问策略。

      Policy

            如果满足同时满足以下条件,就允许Everyone执行。

      SDDL

            D:(XA; ;FX;;;S-1-1-0; (@User.Title=="PM" && (@User.Division=="Finance" || @User.Division ==" Sales")))

 

      Policy

            如果所有用户的任务都和文件的任务相交的话,可以执行。

      SDDL

            D:(XA; ;FX;;;S-1-1-0; (@User.Project Any_of @Resource.Project))

 

      Policy

            如果用户使用一个智能卡登陆那么允许其读访问,这是一个备份操作,并且连接到一个启用了Bitlocker的机器上。

      SDDL

            D:(XA; ;FR;;;S-1-1-0; (Member_of {SID(Smartcard_SID), SID(BO)} && @Device.Bitlocker))

      相关主题

      [MS-DTYP]: Security Descriptor Description Language

 

1.1.3.3 ACE字符串 ACE String

      安全描述符定义语言(SDDL)使用了安全描述符字符串的组成部分DACL和SACL中的ACE字符串。

      正如1.1.3.1 安全描述符字符串格式 中描述的那样,每一个在安全描述符字符串中的ACE都用圆括号包围起来。ACE的域按照下面的顺序用分号分割的。

      注意:条件ACE和其他类型的ACE的格式是不同的。对于条件ACE请参考1.1.3.2 条件ACE的安全描述符定义语言。

 

      域

      ace_type

      一个字符串,描述ACE_HEADER成员AceType的值。ACE类型字符串可以是下面定义在sddl.h中的字符串之一。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      注意:如果一个ace_type是ACCESS_ALLOWED_OBJECT_ACE_TYPE,并且object_guid或inherit_object_guid指定了一个GUID,那么函数ConvertStringSecurityDescriptorToSecurityDescriptor转化ace_type为ACCESS_ALLOWED_OBJECT_ACE_TYPE。

      ace_flags

      一个字符串,指定ACE_HEADER结构AceFlags成员的值。ACE标识字符串可以是下面定义在sddl.h中的字符串的级联。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      rights

      一个字符串,指定由ACE控制的访问权限。这个字符串可以是代表访问权限的十六进制的字符串,比如“0x7800003F”,或者是下面字符串的组合。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      object_guid

      一个表示GUID的字符串,指定了特定对象的ACE结构的ObjectType成员的值,比如说ACCESS_ALLOWED_OBJECT_ACE。GUID字符串使用UuidToString函数返回的格式。

     下表列出了常用的对象GUID。

 

 

 

 

 

 

 

      inherit_object_guid

      一个标识GUID的字符串,指定了特定对象ACE结构的InheritedObjectType成员的值。这个GUID字符串使用UuidToString的格式。

      account_sid

      SID字符串代表了一个ACE的受托者。

      resource_attribute

      [可选的] resource_attribute仅针对资源ACE,并且是可选的。代表了数据类型资源属性ACE数据类型可以是下面定义在sddl.h中的数据类型之一。

      在资源属性中“#”跟“0”是同义词。比如,D:AI(XA;OICI;FA;;;WD;(OctetStringType==#1#2#3##)) 等同于(并翻译为) D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300)).

      Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, and Windows Server 2003:  资源属性是不可用的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      下面的例子显示了一个允许访问ACE的ACE字符串,这不是一个特定对象的ACE,所以在object_guid和inherit_object_guid域中没有信息。ace_flags域也是空的,这说明没有设置任何ACE标记。

 

 

 

      上面的ACE字符串描述了下面的ACE信息。

 

 

 

      下面的例子演示了按照Windows和为具有高度商业影响的带保密SQL要求的资源划分的文件。

 

 

 

      上面给出的ACE字符串描述了下面的ACE信息。

 

 

 

      更多信息,参考1.1.3.1 安全描述符字符串格式和SID字符串。对于条件ACE,参考1.1.3.2 条件ACE的安全描述符定义语言。

      相关主题

      [MS-DTYP]: Security Descriptor Description Language

 

1.1.3.4  SID字符串 SID String

      在1.1.3 安全描述符定义语言(SDDL)中,安全描述符字符串为安全描述符的下列组成部分使用SID字符串。

  • 拥有者
  • 主要用户组
  • ACE中的受托者

      安全描述符中的一个SID字符串可以使用标准字符串表示一个SID(S-R-I-S-S...),也可以使用定义在Sddl.h中的字符串常量。关于标准SID字符串符号的更多信息请参考,1.1.2.1.7.1 SID的结构。

      下列SID字符串常量是定义在sddl.h中的公开SID。关于对应相对IDs(RIDs)的更多信息,请参考公开SIDs。

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      ConvertSidToStringSid和ConvertStringSidToSid函数通常只使用标准SID字符串符号,而不支持SDDL SID字符串常量。

      关于公开SID的更多信息,参考1.1.2.1.7.2 公开的SIDs。

 

1.1.4 特权 Privilege

      特权是一个账户的权限,比如一个用户或组的账号,可以在本地计算机上执行不同的系统相关的操作,比如说关闭系统,加载设备驱动,或者修改系统时间,特权会以两种方式区分访问权:

  • 特权控制对系统资源以及系统相关任务的访问,而访问权限控制对安全对象的控制访问。
  • 一个系统管理员为用户和组账户赋予特权,而系统根据安全对象的DACL中ACE赋予的访问权限,对该对象进行访问权限的赋予或拒绝。

      每个系统都有一个账号数据库,存储了用户和组用户拥有的特权,当一个用户登录的时候,系统生成一个访问令牌,其中包含了一个用户特权的列表,其中包含了用户或用户所属组的特权。注意,特权仅仅用在本地计算机中,一个域账号可以在不同的计算机中有不同的特权。

      当用户尝试执行一个特权操作的时候,系统检查用户的访问令牌来确定用户是否拥有必需的特权,如果有,将会检查该特权是否处于开启。如果这些测试失败了,系统将不执行该操作。

      为了得到访问令牌中的特权,调用GetTokenInformation函数,同时也指出对应的特权将被开启。大多数特权默认关闭。

      Windows API定义了一组字符串常量,比如SE_ASSIGNPRIARYTOKEN_NAME,用来区别不同的特权。这些常量在所有系统中都是一样的,并且定义在winnt.h中。关于Windows定义的特权的列表,参考特权常量。得到和调整一个访问令牌中的特权的函数使用LUID来区分特权。不同计算机,同一个计算机上的不同启动的特权的LUID是不同的。使用LookupPrivilegeValue函数,要得到当前的LUID(与字符串常量之一相关联)。使用LookupPrivilegeName函数把一个LUID转化为与之相关的字符常量。

      系统提供一组可显示的字符串来描述每一个特权,这在你需要给用户提供关于特权的描述的时候非常有用,使用LookupPrivilegeDisplayName函数返回一个关于特权的描述字符常量。例如,在英语操作系统上,显示SE_SYSTEMTIME_NAME特权的名字就是“Change the system time”。

      你可以使用PrivilegeCheck函数来得到一个访问令牌是否有一组指定的特权。这主要是对于模拟成一个客户的服务应用程序非常有用。

      一个系统管理员可以使用管理工具,比如用户管理,来添加、删除用户和组用户的特权。管理员可以使用局部安全性权限(LSA)函数来操作特权。LsaAddAccountRightLsaRemoveAccountRight函数添加和删除一个账号的特权。LsaEnumerateAccountWithUserRight函数可以枚举拥有特享特权的账号。

      相关主题

      授权常量

      用C++打开和关闭特权

 

1.1.5 审查的生成 Audit Generation

      C2级别安全要求系统管理员必须可以审查系统相关的事件,并且对于审查数据的访问仅限于授权管理员。Windows API提供用来监控安全相关的事件的函数。

      一个安全对象的安全描述符可以有一个系统访问控制列表(SACL),一个SACL包含了一组访问控制项(ACE),其指定了生成审查报告的访问尝试的类型。每一个ACE对应一个受托者,一个组访问权限,和一组标记,这个标记指定系统是否要对失败、成功,或者二者皆有的访问尝试生成审查消息。

      系统把审查消息写到安全事件日记中,关于访问安全事件日记中的记录的信息,参考事件日志

      为了读或写一个对象的SACL,线程首先必须打开SE_SECURITY_NAME特权,更多信息参考1.1.2.1.5.4 SACL访问权限。

      Windows API也提供了这样的支持,当一个客户端尝试访问一个私有对象,服务应用程序会生成审查事件。更多信息,参考1.3.6.3 审查对私有对象的访问。

 

1.1.6 安全对象 Securable Objects

      安全对象是一个可以拥有安全描述符的对象。所有命名的Windows对象都是对象安全,一些未命名的对象,比如说进程和线程对象,也可以拥有安全描述符。对于大多数安全对象,你可以在创建这个对象的函数中指定一个对象的安全描述符。比如,你可以在CreateFile和CreateProcess函数中指定一个安全描述符。

      另外,Windows安全函数可以让你得到和设置在操作系统上创建的安全对象的安全信息,且不止在Windows操作系统上。Windows安全函数也提供了对使用带私有的、应用程序定义的对象的安全描述符的支持,更多关于私有安全对象的信息,参考1.3 客户端/服务器访问控制。

      每种类型的安全对象定义了它自己的特定的访问权限,以及通用访问权限的映射。关于各种类型安全对象的特定和通用访问权限的信息,参考对应对象类型的总览。

      下表展示了一些普通安全对象用于管理安全信息的函数。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1.7 低层访问控制 Low-level Access Control 

      低层安全函数可以帮助你操作安全描述符、访问控制列表(ACLs),和访问控制项(ACEs)。

      关于这个模型的描述,参考访问控制模型

 

 

 

 

 

 

 

 

 

 

 

 

1.1.7.1 低层安全描述符的函数 Low-level Security Descriptor Function

      有若干对低层函数来设置和返回对象的安全描述符。每对函数仅能操作一组有限的Windows对象。例如,一对操作文件对象,另一对操作注册表键。下表列出了用于不同类型安全对象的低层函数。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.1.7.2 低层安全描述符的创建 Low-level Security Descriptor Creation

      底层访问控制提供了一组函数来创建安全描述符,并且可以设置和得到安全描述符组成部分。用于初始化和设置安全描述符组成部分的底层函数仅能操作绝对格式的安全描述符。获取安全描述符组成部分的底层函数可以操作绝对和自相对格式的安全描述符InitializeSecurityDescriptor函数初始化一个SECURITY_DESCRIPTOR缓存。这个初始化了的安全描述符是绝对格式的,并且没有拥有者,没有主要用户组,没有用户自定义访问控制列表(DACL),没有系统访问控制列表(SACL)。你可以使用下面的函数来得到和设置指定安全描述符的指定组成部分。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      要检查修订层级和结构化一个安全描述符的整合度,调用IsValidSecurityDescriptor函数。

 

1.1.7.3 绝对的和自相相对的安全描述符 Absolute and self-Relative Security Descriptors

      安全描述符既可以用绝对格式,也可以用自相对格式。用绝对格式的话,一个安全描述符包含一个指向它的信息的指针,而不是包含它的信息。用自相对格式的话,一个安全描述符在一段连续内存中存储一个SECURITY_DESCRIPTOR结构,以及相关的安全信息。要确定一个安全描述符是自相对的还是绝对的,可以调用函数GetSecurityDescriptor函数,并检查SECURITY_DESCRIPTOR_CONTROL参数中的SE_SELF_RELATIVE标记。你还可以使用MakeSelfRelativeSD函数和MakeAbsoluteSD函数在这两种格式之间进行转换。

      当你要创建一个安全描述符,并且拥有其所有组件指针的时候,绝对格式是非常有用的,比如,拥有者、用户组、和用户自定义ACL默认是可用的。这种情况下,你可以调用InitializeSecurityDescriptor函数初始化一个SECURITY_DESCRIPTOR结构,并调用诸如SetSecurityDescriptorDacl之类的函数来为安全描述符的ACL和SID指针赋值。

      使用自相对格式,一个安全描述符经常以一个SECURITY_DESCRIPTOR结构开始,但是其他安全描述符的组件可以按任何顺序跟在这个结构之后。安全描述符的组件使用相对描述符开始的偏移来定位,而不是内存地址。当安全描述符必须存放在硬盘上,并且使用协议来交互,或者在内存中拷贝的时候,这种格式是非常有用的。

      除了MakeAbsoluteSD,所有返回安全描述符的函数都适用自相对格式。用作参数传递给函数的安全描述符既可以是绝对,也可以是自相对的。详情请参考相应函数的说明。

 

1.1.7.4 低层ACL和ACE函数 Low-level ACL and ACE Functions

      要创建一个访问控制列表(ACL),可以使用底层函数,为ACL申请内存,然后使用InitializeAcl函数初始化之。要添加访问控制项(ACE)到用户自定义访问控制列表(DACL)的末尾,可以使用AddAccessAllowedAce和AddAccessDeniedAce函数。AddAuditAccessAce函数在系统访问控制列表(SACL)末尾添加一个ACE。AddAce函数允许你添加一个可继承的ACE到ACL中。DeleteAce函数从指定的ACL中移除一个ACE。GetAce函数从一个ACL中指定位置上得到一个ACE。FindFirstFreeAce函数返回一个ACL中第一个未使用字节的指针。

      要修改一个对象的安全描述符中已存在的ACL,可以使用GetSecurityDescriptorDacl或者GetSecurityDescriptorSacl函数得到这个已存在的ACL。你可以使用GetAce函数从一个ACL中拷贝ACE。申请并初始化一个新的ACL之后,使用诸如AddAccessAllowedAce和AddAce函数添加ACE。当你完成创建一个新的ACL之后,使用SetSecurityDescriptorDacl和SetSecurityDescriptorSacl函数来添加新的ACL到对象的安全描述符中。

      你可以使用AddAccessAllowedObjectAce,AddAccessDeniedObjectAce,或者AdAuditAccessObjectAce函数把一个指定对象的ACE添加到一个ACL末尾。

 

1.2 访问控制编辑器 Access Control Editor

      访问控制编辑器是一组属性表(Sheet)和属性页(page),它允许用户查看和修改对象安全描述符的组成部分。编辑器由两个主要部分组成:

  • 一个基本安全属性页,提供了一个简单的接口来编辑一个对象的自定义访问控制列表(DACL)中的访问控制项(ACE)。这页能包含一个展示高级安全属性页的可选的高级按钮。
  • 一个带有属性页的高级安全属性,可以让用户编辑对象的系统访问控制列表(DACL),修改对象的拥有者,执行对象DACL的高级编辑。

      CreateSecurityPage函数创建基本安全属性页。你可以使用PropertySheet函数或者PSM_MESSAGE消息添加这个属性页到一个属性表。

      另外,你可以使用EditSecurity函数来显示一个包含基本安全属性页的属性表。

      对于CreateSecurityPage和EditSecurity,调用者必须传递一个ISecurityInformation的实现的指针。访问控制编辑器调用这个接口的方法来返回被编辑的对象的访问控制信息,并把用户的输入传递返回给你的应用程序。ISecurityInformation有一下目的:

  • 初始化属性页。

      你实现的GetobjectInformation方法传递一个SI_OBJECT_INFO结构给编辑器。这个结构指定了你想要编辑器显示的属性页。以及其他一些判断是否对用户可用的编辑选项。

  • 提供被编辑对象的安全信息。

      你对GetSecurity的实现会传递对象的初始安全描述符给编辑器。GetAccessRights和MapGeneric方法提供了对象访问权限的信息。GetInheritTypes方法提供了对象的ACE如何被子对象继承的信息。

  • 给你的应用程序传递用户的输入。

      当用户点击Okay或者Cancel的时候,编辑器调用你的SetSecurity方法来传递回一个包含用户改变的安全描述符。

 

1.2.1 基本安全属性页 Basic Security Property Page

      基本安全属性页是由EditSecurity函数展示的第一个属性页。你也可以通过CreateSecurityPage函数创建一个基本属性页来插入到你自己的属性表。

      属性页展示了在对象自定义访问控制列表(DACL)中一个命名的访问控制项(ACE)的受托者列表。这个页面也包含一个由对象支持的访问权限列表。当用户从受托者中选中一个名字之后,每个访问权限旁边的复选框表示的是该权限对于受托者而言是允许还是拒绝。用户可以选择或者清空复选框来修改受托者的访问权限。用户也可以从列表中添加或删除受托者。

      基本安全属性页不能显示复杂的ACE,比如对象专属的ACE,或者ACE继承信息。要让用户查看或者编辑此类信息,你需要在基本安全页包含一个高级按钮。用户可以点击高级按钮显示一个高级安全属性表。这个属性表中的属性页允许用户编辑对象的系统访问列表(SACL),改变对象的拥有者,执行对象的DACL的高级编辑。要显示该高级按钮,就要在你的ISecurityInformation::GetObjectInformation实现返回的SI_OBJECT_INFO结构中的设置SI_ADVANCED标志。

      你可以使用SI_OBJECT_INFO结构的pszPageTitle成员指定基本安全属性页的标题,默认的标题是安全。

 

1.2.2 高级安全属性页 Advanced Security Property Sheet

      高级安全属性表允许用户对一个访问控制编辑器执行在基本安全属性页中没有的编辑操作。属性表可以包含下面的属性页:

  • 权限属性页,可以对对象的自定义访问控制列表(DACL)进行高级编辑,比如编辑对象专属的ACE或者控制ACE的继承。
  • 审核属性页,查看和编辑对象的系统系统访问控制列表(SACL)。
  • 拥有者属性页,修改对象的拥有者。

      用户可以点击基本安全属性页中的高级按钮显示高级安全属性。要显示高级按钮,就要在你的ISecurityInformation::GetObjectInformation实现返回的SI_OBJECT_INFO结构中的设置SI_ADVANCED标志。

 

1.2.3 许可属性页 Permission Property Page

      权限属性页包含对一个对象的DACL的高级编辑控制项。这页允许用户查看和编辑DACL中的所有信息,包括基本安全属性页中不可用的信息。高级信息包括对象专属ACE和ACE继承性的信息。

      当用户点击基本安全属性页中的高级按钮时,权限属性页通常包含在高级安全属性表中,

 

1.2.4 审查属性页 Audit Property Page

      访问控制编辑器可以包含一个审核属性页,允许用户查看和编辑对象的系统访问控制列表(SACL)中的访问控制项(ACE)。更多关于SACL的信息,参考 1.1.2.1.3访问控制列表(ACL)。

  • 在基本安全属性页中,点击高级按钮,审核属性页就在高级安全属性表中。

      要包含审核属性页,就要在你的ISecurityInformation::GetObjectInformation实现返回的SI_OBJECT_INFO结构中的设置SI_ADVANCED和SI_EDIT_AUDITS标志。

 

1.2.5 拥有者属性页 Owner Property Page

      访问控制编辑器可以包含一个拥有者属性页,允许用户修改一个对象的拥有者。更多关于对象的拥有者的信息,参考 1.1.2.1.2.2.3 新对象的拥有者和 2.4.8 使用C++获取对象的拥有者。

      当用户点击基本安全属性页中的高级按钮时,高级安全属性表中的拥有者属性页就会显示。要包含拥有者属性页,就要在你的ISecurityInformation::GetObjectInformation实现返回的SI_OBJECT_INFO结构中的设置SI_ADVANCED和SI_EDIT_OWNER标志。

 

1.3 C/S访问控制 Client/Server Access Control

      服务程序为客户端提供服务,比如一个服务可能代表一个客户端执行下面的服务:

  • 在一个私有数据库中保存和返回数据。
  • 访问网络资源
  • 在服务器计算机的客户端安全上下文中开启进程

      受保护的服务控制者对其服务的访问,Windows提供了让一个服务做以下服务的安全支持。

  • 实现一个客户端安全上下文,这使得系统可以根据客户端的访问令牌而不是服务器的访问令牌来执行大多数访问和特权检查。
  • 把一个客户端登陆到服务器计算机上
  • 使用客户端安全上下文连接网络资源
  • 创建一个安全描述符来保护私有对象
  • 确定一个安全描述符是否允许访问一个客户端
  • 确定一个客户端的访问令牌中的一组特权是否被激活
  • 在安全事件日志中生成审核消息,记录客户端访问对象的尝试,或者使用的特权。

 

1.3.1 客户端安全上下文 The Client Security Context

      跟所有进程类似,一个受保护的服务有一个描述其安全上下文的主要访问令牌。当一个客户端连接到受保护服务的时候,服务可能想要使用客户端的安全上下文而不是服务的。比如一个动态数据交换(DDE)从一个DDE服务转换请求的信息,服务需要确定客户端是被允许访问这个信息的。

      一个服务可以根据客户端的安全上下文用两种方式进行模拟:

  • 服务进程的一个线程可以模拟客户端。在这种情况下,服务的线程有一个模拟访问令牌来标识客户端、客户端的组和客户端的特权。更多信息参考 1.3.2 客户端模拟。
  • 服务可以获得客户端的证书,并把客户端登陆到服务所在的计算机上。这会创建一个新的登录会话,并为客户端生成一个主要访问令牌。然后服务可以使用客户端的访问令牌来模拟客户端,开启一个新进程,并使用客户端的安全上下文。更多信息参考 1.3.3 客户端登录会话。

      大多数情况下,模拟客户端是足够的。模拟动作可以让服务检查客户端对安全对象的访问,检查客户端的特权,并生成审核足迹项来标识客户端。一般地,一个服务仅在它需要使用客户端的安全上下文访问网络的时候才需要开启一个客户端登录会话。

 

1.3.2 客户端模拟 Client Impersonation

      模拟是一个线程使用不同的安全信息运行的一种能力,而非使用线程所属进程的安全信息。一般地,一个服务应用中的线程模拟一个客户端。这使得服务线程代表客户端访问服务中的对象,或者验证客户端的拥有对象的访问。

      微软的Windows API提供了一下函数来开始一个模拟操作:

  • 一个动态数据交换(DDE)服务应用可以调用DdeImpersionateClient函数来模拟一个客户端。
  • 一个命名管道服务可以调用ImpersonateNamedPipeClient函数。
  • 你可以调用ImpersonateLoggedOnUser函数来模拟一个登录用户的访问令牌的安全上下文。
  • ImpersonateSelf函数允许一个线程生成自身访问令牌的一个拷贝。当一个应用需要修改一个单线程的安全上下文的时候是非常有用的。比如,有时候进程中仅有一个线程需要拥有一个特权。
  • 你可以使用SetThreadToken函数在指定的模拟令牌安全上下文中启动目标线程。
  • 一个微软远程过程调用(RPC)服务应用可以调用RpcImpersonateClient函数来模拟一个客户端。
  • 一个安全包或者应用服务可以调用ImpersonateSecurityContent函数来模拟一个客户端

      对于大多数模拟,模拟线程可以通过调用RevertToSelf函数来反转自己的安全上下文。例外是RPC的模拟,这种情况下RPC应用调用RpcRevertToSelf或者RpcRevertToSelfEx函数来反转它自己的安全上下文。

 

1.3.2.1 模拟级别 Impersonation Levels

      枚举类型SECURITY_IMPERSONATION_LEVEL定义了四个模拟级别,这些级别决定了一个服务可以在客户端上做的操作。

 

 

 

 

 

 

 

 

 

 

 

 

      命名管道、RPC、或者DDE连接上下文可以控制模拟级别。例如,一个命名管道客户端可以调用CreateFile函数来打开一个命名管道的句柄,并制定服务的模拟级别。

      当命名管道、RPC、或者DDE连接是远程的传递给CreateFile设置模拟级别的标记将会被忽略。这种情况下,客户端的模拟级别由服务激活的模拟级别决定,而这个级别由目录服务上的服务账号设置。例如,服务是为代理激活的,即便传递给CreateFile的标记指定了模拟级别身份,客户端的模拟级别也会被设置为代理。

      DDE客户端使用DdeSetQualityOfService函数,并用SECURITY_QUALITY_OF_SERVICE结构指定模拟级别。命名管道、RPC、和DDE服务的默认级别是SecurityImpersonation。ImpersonnateSelfDuplicateTokenDuplicateTokenEx函数允许调用者指定模拟级别。使用GetTokenInformation函数来获得访问令牌的模拟级别。

      在SecurityImpersonation级别上,多数线程的动作发生在线程的模拟令牌的安全上下文中,而不是线程所在进程的主要令牌中。例如,如果一个模拟线程打开了一个安全对象,系统使用模拟令牌来检查线程的访问。同样地,如果一个模拟线程创建了一个新对象,比如说,用CreateFile函数,这个新对象的拥有者就是客户端的访问令牌的默认拥有者。

      然而,在以下情形中,系统使用进程的主要令牌而不是调用线程的模拟令牌:

  • 如果一个模拟线程调用CreateProcess函数,新的进程常常继承了进程的主要令牌。
  • 对于需要SE_TCB_NAME特权的函数,比如LogonUser函数,系统总是检查进程的主要令牌。
  • 对于需要SE_AUDIT_NAME特权的函数,比如ObjectOpenAuditAlarm函数,系统总是检查进程主要令牌的特权。
  • 调用OpenThreadToken时,线程可以指定是使用模拟令牌还是主要令牌从而决定是否授予请求 的访问。

 

1.3.2.2 模拟令牌 Impersonation Token

      一个模拟令牌有两访问令牌:

  • 一个主要访问令牌,描述了服务的安全上下文。要得到这个令牌的句柄,调用OpenProcessToken函数。
  • 一个模拟访问令牌,描述了要模拟的客户端的安全上下文。要得到这个令牌的句柄,调用OpenThreadToken函数。

      一个服务在以前情形中可以使用模拟令牌:

  • 用函数AccessCheck、AccessCheckByByte和AccessCheckByTypeResultList判断一个安全上下文是否允许客户端一组访问权利时。
  • 用函数AdjustTokenPrivilege激活或禁用客户端的特权时。
  • 用PrivilegeCheck函数确定一组特权是否在客户端令牌中激活时。
  • 用生成安全事件日志中的项的函数,比如ObjectOpenAuditAlarm或PrivilegeServiceAuditAlarm。这些函数使用模拟令牌来得到关于客户端的日志项的信息。

 

1.3.3 客户端登陆会话 Client Logon Sessions

      带有SE_TCB_NAME特权的服务,比如一个运行在本地系统账号上的Windows服务,可以调用LogonUser函数向一个运行服务的计算机授权。LogonUser函数启动一个新会话,并返回一个包含了客户端安全信息的主要访问令牌。你可以在ImpersonateLoggedOnUser函数中使用这个主要访问令牌来模拟客户端,或者调用CreateProcessAsUser函数来创建一个运行在客户端的安全上下文中的进程。

 

      以这种方式授权客户端的优点是,服务模拟授权客户端,或者模拟在授权客户端中创建的一个进程,可以以客户端身份连接远程网络资源。如果这个授权不能执行,服务仅当获得客户端传递给WNetAddConnection2函数的账户名和密码才能连接网络资源。

      以这种方式授权客户端的缺点是,服务必须得到客户端的凭证(域名,用户名,和密码)。如果一个远程客户端为服务器提供这些的凭证,那么客户端和服务就有责任保证这些凭证以一种安全的方式传输。

 

1.3.4 客户端安全上下文中的进程 Processes in the Client Security Context

      服务应用可以调用CreateProcessAsUser函数来创建一个在用户端上下文中运行的新进程。调用时使用客户端的访问令牌,CreateProcessAsUser要求SE_ASSIGNPRIMARYTOKEN_NAME和SE_INCREASE_QUOTA_NAME特权,这些特权由在本地系统账户中运行的Windows服务管理着。

      CreateProcessAsUser函数同样需要一个主要访问令牌。一个服务可以通过为客户端启动一个登录会话、或者模拟一个客户端并复制模拟访问令牌来得到客户端的主要访问令牌。

      下面的过程描述了创建一个客户端进程的两种方法:

      通过登录到客户端创建一个客户端进程

  1. 在对LogonUser的调用中使用客户端的证书把客户端登录到本地系统。LogonUser为客户端的登录会话产生一个主要访问令牌。
  2. 如果服务需要使用客户端的安全上下文,就需要通过使用主要访问令牌调用ImpersonateLogonedOnUser函数来得到客户端进程的可执行文件的访问权。
  3. 调用CreateProcessAsUser时使用主要访问令牌在客户端上下文中创建一个进程。

      注意 使用下述技术创建的进程可能不能访问网络资源,除非它有客户端的证书。

      通过模拟客户端创建客户端进程

  1. 通过使用模拟函数开始一个模拟操作,比如ImpersonateNamedPipeClient。
  2. 调用OpenThreadToken函数来得到一个含有客户端安全上下文的模拟访问令牌。
  3. 调用DuplicateTokenEx函数来把模拟访问令牌转换为主要访问令牌。
  4. 在CreateProcessAsUser中使用主要访问令牌在一个客户端安全上下文中创建一个进程。

      默认情况下,CreateProcessAsUser在一个非交互的工作站或桌面上创建一个客户端进程。要创建一个交互程序,服务必须首先要设置交互工作站或桌面的用户自定义访问列表(DACL),以保证客户端可以访问这些资源。较好的办法是让登录客户端,得到客户端的登录会话的安全身份(SID),然后在交互式Windows工作站和桌面上允许访问的ACE中使用这个SID。服务可以调用CreateProcessAsUser,指定默认的交互Windows工作站和桌面。关于这个过程的示例,参考使用C++开启一个交互客户端进程

 

1.3.5 客户端访问网络资源 Client Access to Network Resources

      服务可以使用下面的策略访问网络资源:

  • 如果服务有客户端的账户名和密码,服务可以使用客户端的证书调用函数WNetAddConnection2来映射本地驱动字母到网络共享。
  • 在使用客户端证书调用LogonUser之后,服务可以调用CreateProcessAsUser函数来为客户端创建一个进程。这个新的客户端进程可以使用客户端的安全上下文来访问网络资源。例如,这个进程可以调用CreateFile函数打开一个远程电脑的文件。系统使用客户端的主要访问令牌来检查客户端进程的访问尝试。
  • 服务可以使用一个空的证书调用WNetAddConnection2,来建立一个到带服务访问网络资源的连接或者默认连接。如果服务作为本地系统账户运行,它会授权给域服务安全上下文下的网络资源。如果服务在服务账户下运行,那么服务就会授权为这个账户。更多信息参考本地系统账户。

      关于保护密码的更多信息,参考管理密码。关于获得证书的更多信息,参考请求用户证书

 

1.3.6 基于ACL的访问控制  ACL-based Access Control

      正如系统使用安全描述符来控制对安全对象的控制一样,一个服务可以使用安全描述符来控制对它的私有对象的访问。关于Windows安全模型的更多信息,参考访问 1.1.2控制模型。

      一个受保护的服务可以使用一个指定了各种受托者可访问类型的DACL创建一个安全描述符。在一个简单案例中,服务可以创建一个单安全描述符来控制对服务的数据和功能的访问。想要一个更好粒度的保护,服务可以为它的每一个私有对象、或者不同的功能创建安全描述符,

      例如,当一个客户端请求服务在数据库中创建一个新对象,服务可以为这个新对象创建一个新的安全描述符。之后,服务可以把这个安全描述符和私有对象一起存储在数据库中。当一个客户端尝试访问这个对象时,服务返回这个安全描述符来检查这个客户端的访问权。这里要注意,这个安全描述符中没有任何与受保护的对象或功能相关的东西。取而代之的是,这取决于受保护服务如何维护这些相关项。

      访问这些私有对象,也可以被审查。参考 1.3.6.3 审查私有对象的访问 得到更多描述。

 

1.3.6.1 私有对象的安全访问描述符 Security Descriptors for Private Objects

      要创建安全描述符,受保护服务可以使用和应用程序为安全对象创建安全描述符相同的流程。示例代码,参考 2.4.4.2 用C++为一个新对象创建安全描述符。另外,一个受保护服务应用可以调用BuildSecurityDescriptor函数来完成这个工作。如果为BuildSecurityDescriptor提供一个指向一个存在的自相关安全描述符的指针,函数会使用这个安全描述符的信息创建一个新的安全描述符,这时候的安全描述符信息合并了函数调用时传递给参数的控制信息。拥有者和组由传递给函数的TRUSTEE结构指定,这个是可选的。由BuildSecurityDescriptor创建的安全描述符是自相关格式的。

      另外,Windows API提供了一组函数用于合并客户端安全信息和继承自父对象或者一个默认安全描述符的信息。CreatePrivateObjectSecurityGetPrivateObjectSecuritySetPrivateObjectSecurityDestroyPrivateObjectSecurity函数提供了从一个访问令牌中获取默认信息的能力,支持继承、和管理安全描述符中的特定部分。这当客户端在安全对象架构中创建一个私有对象的时候是很有用的。比如,你可以使用CreatePrivateObjectSecurity函数创建一个安全描述符,让它包含由客户端指定的ACE,从父对象继承的ACE,来自创建客户端访问令牌的默认拥有者。当BuildSecurityDescriptor创建安全描述符时使用的访问控制信息,或者来自传递到函数调用的访问控制信息,或者来自一个已存在的安全描述符,CreatePrivateObjectSecurity创建一个安全描述符仅仅来自一个已存在的安全描述符中的信息。

      LookupSecurityDescriptorParts函数获得安全描述符信息来自一个已存在的自相关安全描述符。这个信息包括指定的拥有者和组,SACL或DACL中ACE的数量,以及SACL或DACL中的列表。

 

1.3.6.2 检查私有对象的访问 Checking Access to Private Objects

      受保护服务应用必须在允许客户端访问受保护私有对象之前检查一个客户端的访问权限。为此,服务要传递一个模拟访问令牌,一个安全描述符,和一组AccessCheck要求的访问权限。安全描述符的DACL中的ACEs指定了对于不同受托者允许访问或者拒绝访问。函数AccessCheck对比ACE中的每个受托者和定义在模拟访问令牌中的受托者。关于赋予和拒绝访问的算法描述,参考 1.1.2.2 访问检查是如何工作的

      AccessCheckAndAuditAlarm函数执行一个类似的访问检查。另外,它还根据安全描述符中的SACL在安全事件日志中生成一个审查记录。

      函数AccessCheckByTypeAccessCheckByTypeAndAuditAlarmAccessCheckAccessCheckAndAuditAlarm,除了还允许你检查对一个对象的子对象的访问,比如属性子集或者是属性。AccessCheckByTypeResultListAccessCheckByTypeResultListAndAuditAlarm函数同AccessCheck类似,除了它们按照对象的属性和属性集合层次为每个子对象提供一个访问检查结果。这些函数使用OBJECT_TYPE_LIST结构来描述对象的访问检查的层次结构。生成审查消息的函数使用AUDIT_EVENT_TYPE枚举类型来指示正在审查的这个对象是否是一个目录服务对象。关于对象和它的子对象的层次的信息,参考 1.1.2.1.4.7 对象属性控制访问的ACEs

      传递给AccessCheck和AccessCheckAndAuditAlarm函数要求的访问权限一定不能包含任何通用访问权限。服务能够使用MapGenericMask函数根据GENRIC_MAPPING结构体中指定的映射把任何通用访问权限转化到对应的特定的和标准的权限。

      AreAllAccessesGrantedAreAnyAccessesGranted函数会比较请求的访问掩码和授权的访问掩码。

      使用AccessCheck函数的代码示例,参考 2.4.6 用C++区分带ACLs的客户访问。

      ConvertToAutoInheritPrivateObjectSecurity函数会以允许自动传播可继承的ACEs的形式创建并返回一个安全描述符。这个安全描述符以自相关的形式包含所有的ACE,包括已继承的和不可继承。ConvertToAutoInheritPrivateObjectSecurity函数通过对比当前安全描述符中的所有ACEs和它的父安全描述符中的所有ACEs来决定某个ACE是可继承的还是不可继承的。在两组ACEs之间不一定是一对一的相关。比如,一个允许读/写许可的ACE可以等于两个ACE:一个允许读的ACE,和一个允许写的ACE。一个父安全描述符。如果当前的安全描述符就是父安全描述符的话,那么它可能就没有父安全描述符。

 

1.3.6.3 审查私有对象的访问 Auditing Access to Private Objects

      一个受保护的服务可以通过下列函数在安全事件日志中生成审查报告。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.4 应用程序资源访问控制 Access Control for Application Resources

      授权管理API和Windows Server 2003中可用的的MMC管理单元提供了带有一个灵活的、基于角色的控制框架的程序。这个框架包含一组对于web和商业应用程序线而言是可剥离的COM对象。

      下面的两个章节提供了关于控制访问应用程序资源的信息。

 

1.4.1 基于角色的访问控制 Role-based Access Control

      授权管理API和MMC管理单元提供一个基于角色的访问控制框架的应用程序。授权管理API,也被称为AzMan,提供了一个简化了的开发模型,该模型管理灵活的组和商业规则,并存放授权策略。详情参考下面的话题:

      Windows XP:授权管理API和MMC管理单元可以从http://www.microsoft.com/downloads下载。这个链接下载提供授权管理策略管理和开发:不支持使用了授权管理控制访问的应用程序的部署。

      相关主题

授权接口

授权对象

使用C++授权

使用脚本授权

 

1.4.1.1 基于角色访问的优势 Advantage of Role-based Authorization

      授权管理API提供一个授权模型,该模型在底层(基于ACL)授权上有很多优势:

  • 简化访问控制管理
  • 使授权对于脚本和使用Microsoft Visual Basic开发系统开发的应用是可用的
  • 提供一个机制,当检查访问的时候应商业逻辑

 

1.4.1.2 授权管理模型 Authorization Manager Model

      授权管理提供一个灵活的框架,为了整合基于模型访问控制到应用程序。它可以让使用那些应用程序的管理员通过赋予用户与任务功能相关的角色来提供访问。

      授权管理应用以存储在活动目录或XML文件和授权贮存格式存储授权策略,并在运行时应用授权。

      应用程序然后调用一个运行时访问检查方法,该方法根据授权贮存中的策略信息检查访问。

      授权策略包含下列部分:

  • 策略存储,应用程序,和范围
  • 用户和组
  • 操作和任务
  • 角色
  • 商业规则
  • 集合

 

1.4.1.2.1 策略存储、应用程序、和范围 Policy Stores、Applications、and Scopes

      授权策略的存储,应用程序和范围代表了授权管理策略的不同组织层次。一个策略的存储可以包含一个或多个应用程序,一个应用程序可以包含一个或多个范围。

授权策略存储

      在授权管理API中,一个授权策略用一个IAzAuthorizationStroe对象表示。授权策略存储包含应用程序、范围、操作、任务、角色、和用户组的定义和赋值。

      一个授权策略存储可以存储在XML文件或者活动目录中。

      一个应用程序在修改存储的信息、或者使用储存策略检查客户端对资源的访问前,必须初始化一个授权策略存储。

      一个授权策略可以包含一个或多个IAzApplication对象,这些对象代表了指定应用的授权策略。

应用程序

      在授权管理API中,一个应用程序使用一个IAzApplication对象来表示。一个授权策略存储可以包含多个应用程序的授权策略信息。使用IAzApplication对象可以让你用一种策略存储来为不同的应用程序存储不同的授权策略。

      一个授权策略存储必须包含至少一个应用程序。

范围

      在授权管理API中,一个范围使用一个IAzScope对象表示。范围为授权策略提供了附加的、可选管理层次。一个应用程序可以包含一个或多个范围,但不必包含任何(授权管理提供一个默认的、应用程序级别范围)。

      范围是一个程序内的细分,而这个程序是区分其他程序使用的资源的。如果你有授权管理组,角色定义,或者你不想应用到某个应用程序的任务定义,你可以在范围这一级别创建它们。

托管

      存储在活动目录的授权策略贮存支持管理托管。可以托管这个管理到这个贮存、应用程序、或者范围级别中的用户和组。每一层级都为这个层级的策略定义了管理角色。要给某个用户或组托管控制,可以赋予他们管理员角色;要允许用户或组读取策略,可以赋予他们读者角色。

      一个贮存、应用程序、范围的管理员可以读取和修改那个托管层级的策略存储。读者可以在托管层级读取这个策略存储,但是不能修改存储。

相关主题

2.4.1.1 用C++创建授权策略存储对象

2.4.1.2 用C++创建应用程序对象

2.3 用C++托管许可的定义

 

1.4.1.2.2 用户和组 Users and Groups

      在授权管理中,授权策略的接受者用下面的组表示:

  • Windows用户和组

      这些组包含用户,计算机,和满足安全原则的内置组。

  • LDAP查询组

      这些用户组中的成员根据轻量目录访问协议(LDAP)查询需求动态计算得到。一个LDAP查询组是一种应用程序组。

  • 基本应用程序组

      这些组由LDAP查询组、Windows用户和组、和其他基本应用程序组构成。

Windows用户和组

      这些组类似于Windows操作系统中的用户和组。

LDACP查询组

      在授权管理中,你可以使用LDAP查询来匹配用户的属性和那些活动目录中用户的对象。

      比如,下面的查询会找到所有用户,但是除了Andy。

 

      下面的查询会找到所有www.fabrikam.com的成员。

 

  • 基本应用程序组

      在授权管理API中,一个应用程序组使用IAzApplicationGroup对象来表示。一个基本应用程序组是应用程序组类型的。

      要定义基本应用程序组成员,要定义谁是成员,谁不是成员。这两步都以同样的方式执行。在指定零个或多个Windows用户和组之前,要先定义基本应用程序组,或者LDAP查询组。这个基本应用程序组的成员会在移除该组任何非成员的时候计算。授权管理会在运行时自动计算。

      基本应用程序组中的非成员会优先于成员执行。

      闭环成员关系定义是非法的,这回导致以下错误信息:“不能添加组名。发生下面的问题:检测到一个循环。”

相关主题

2.4.1.6 用C++定义用户组

 

1.4.1.2.3 操作和任务 Operations and Tasks

      一个操作是一个底层的动作。在授权管理API中,一个操作用一个IAzOperation对象来表示。一般来说,操作由于过于繁多并且过于底层,对于管理是不方便的。任务相关的组操作可以简化授权策略管理。

      一个任务使用一个IAzTask对象表示,可以包含一个或多个IAzOperation对象。一个IAzTask对象可以包含其他的IAzTask对象,以便任务可以嵌套。为了简化管理,一个IAzTask对象应该代表一个用户真的想要执行的任务。

      访问一个任务包含的操作可以在运行时通过一个与代表这个任务的IAzTask对象相关的商业规则脚本来进行授权。关于商业规则脚本,详情参考商业规则

      通过设置IsRoleDefinition为TRUE,一个IAzTask对象也可以代表一个角色定义。授权管理MMC管理单元用户接口然后展示IAzTask对象为一个角色。更多关于角色的信息参考角色

相关主题

2.4.1.3 用C++定义操作

2.4.1.4 用C++把操作打包到任务中

2.4.1.5 用C++把任务打包到角色中

1.4.1.2.2 用户和组

 

1.4.1.2.4 角色 Roles

      在授权管理中角色服务于两种目的。一个角色是某种分类用户请求访问的一组任务或操作,同时也是符合这种分类的一组用户和组。

作为任务组集合的角色

      一个授权策略把一个IAzTask对象赋值给一个IAzRole对象,来创建任务组。所有用户和组赋值到那个IAzRole对象之后,就可以房屋内由那些IAzTask对象包含的所有操作。

      因为一个IAzRole对象代表一组任务和可以访问那些任务的一组用户和组。授权管理提供了一种方法来创建可以赋值给多于一个IAzRole对象的角色定义。一个IAzTask对象可以包含其他IAzTask对象。你可以使用这个IAzTask对象作为一个角色定义赋值给一个或多个IAzRole对象。设置IAzTask对象的IsRoleDefinition属性为TRUE使授权管理MMC管理单元用户接口显示IAzTask为一个角色。

所谓用户和组集合的角色

      调用AddMember和AddMemberName方法,为用户和组赋予IAzRole对象来授权,使得这些用户和组可以访问赋值给IAzRole对象的任务。调用AddAppMember方法,可以为由IAzApplicationGroup对象代表的已有应用程序组赋值。所有赋予IAzRole的用户和组可以访问赋予那个角色的任务和操作。关于应用程序组的更多信息参考1.4.1.2.2 用户和组。

相关主题

2.4.1.5 用C++把任务打包到角色

2.4.1.6 用C++定义用户组

2.4.1.7 用C++添加用户到应用程序组

 

1.4.1.2.5 商业规则 Business Rules

      一个商业规则可以让一个程序在运行时使用逻辑验证赋予客户端的资格。

      一个商业规则是一个用VBScript编程语言或者与IAzTask对象有关的微软JScript开发软件写成的脚本。当应用程序检查对一个操作的访问时,授权管理首先检查当前的客户端是否访问了任何包含这个操作但是没有关联商业规则的任务。如果这个访问没有这样授权,授权管理会运行包含这个操作的所有任务相关的商业规则脚本。

      一个应用程序用一对表示名字和值的数组参数传递给商业规则脚本。

      一个商业规则脚本不能赋值给一个包含在托管范围中的任务。

相关主题

2.4.3 用C++写的商业逻辑验证访问

 

1.4.1.2.6 集合 Collections

      授权管理API提供表示其他对象集合的接口。例如IAzRole接口表示一个IAzRole对象的集合。

      其他代表集合的接口是IAzApplication、IAzApplicationGroups、IAzOperations、IAzScopes和IAzTasks。每一个接口都提供了简化枚举集合中对象的属性。

 

1.5 强制诚信控制 Mandatory Integrity Control

      强制诚信控制(MIC)提供了一种对安全对象访问的控制机制。这种机制是随意访问控制和计算访问的补充,发生在对一个对象的用户自定义访问控制列表的计算访问检查之前。

      MIC使用诚信层级和强制策略来计算访问。赋值给安全原则和安全对象的诚信层级决定了它们的保护和访问层级。比如,一个拥有低诚信的原则不能对一个拥有中等诚信层级的对象写操作,即使是这个对象的DACL允许原则的写访问。

      Windows定义了四种诚信层级:低级、中级、高级、系统级。标准用户对应中级,提升用户对应高级。你启动的进程、创建的对象对应的是你的诚信级别(中级或者高级),如果可执行文件是低级那么也是低级;系统服务对应的是系统级别的诚信。缺少一个诚信标签的对象会被操作系统当做中级;这样可以防止低级别代码修改无标签的对象。另外,Windows保证运行在低级诚信上的进程不能获得访问一个与app容器相关的进程的权限。

诚信标签

      诚信标签指定了安全对象和安全原则的诚信级别。诚信标签由诚信SID表示。安全对象的诚信SID存储在系统访问控制列表(SACL)中。SACL包含一个SYSTEM_MANDATORY_LABLE_ACE的ACE,这个ACE反过来又包含了这个诚信SID。任何没有诚信SID的对象都会被当做拥有中级诚信。

      安全原则的诚信SID存放在它的访问令牌中。一个访问令牌可以包含一个或多个诚信SID。

      关于诚信SID的定义,详情参考 1.1.2.1.7.2 公开的SID。

进程的创建

      当一个用户尝试加载一个可执行文件,一个使用最低的用户整合性层级和文件整合性层级的进程就被创建了。这意味着新的进程的执行层级永远不会比可执行文件诚信层级高。如果管理员用户执行一个低层级的程序,相应的新进程的访问令牌就是低层级的。这可以帮助加载不可信代码的用户免受恶意行为的影响。用户数据(典型的用户诚信层级)是对新进程写保护的。

强制策略

      安全对象的SACL中的SYSTEM_MANDATORY_LABEL_ACE包含一个访问掩码,这个掩码指定主要的诚信层级访问权限低于赋予对象的访问权限。为这个访问掩码定义的值有SYSTEM_MANDATORY_LABEL_NO_WRITE_UP、SYSTEM_MANDATORY_LABEL_NO_READ_UP、和SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP。默认情况下,系统创建的每个对象都是使用访问掩码SYSTEM_MANDATORY_LABEL_NO_READ_UP。

      每一个访问令牌也会指定一个强制策略,这个在创建令牌的时候由本地安全授权(LSA)设置。这个策略由一个与令牌相关的TOKEN_MANDATORY_POLICY结构指定。调用GetTokenInformation函数并给TokenMandatoryPolicy设置TokenInformationClass参数值来查询这个结构。

 

1.6 用户账户控制 User Account Control

      用户账户控制(UAC)可以让用户以非管理员身份执行普通任务,调用标准用户,不需要切换用户、注销、或者使用Run As就切换到管理员身份。UAC行为中的“从不通知”设置不再禁用UAC。设置“从不通知”使你一个分离令牌,并一直允许自动提升请求的特权。这些微妙的变化可能会给你的app带来兼容性上的问题。你也可以使用组策略或者手动设置注册表禁用UAC。

      Windows Server 2008 R2,Windows 7,Windows Server 2008,和Windows Vista:设置“从不通知”会禁用UAC。

      例如,如果你通过以下步骤修改“从不通知”设置,你就会在要求提升权限的文件夹中创建文件时得到不同的结果。Windows 8会拒绝访问。Windows 7允许你创建爱你File.txt文件。

  1. 打开“开始“菜单,在搜索框中键入”更改用户账户控制设置“。
  2. 点击”更改用户账户控制设置“打开。
  3. 移动滑块到”从不通知“。
  4. 点击”确认“。
  5. 重启操作系统。
  6. 打开运行对话框,输入”cmd.exe“。注意窗口标题不再包含”管理员“字符串。
  7. 键入"echo > %windir%\system32\File.txt"。

 

      UAC在Windows Server 2008和Windows Vista的时候加入。一个标准用户账户和Windows XP中的一个用户账户是同义词。本地管理员组的成员用户账户以标准用户身份运行大多数应用程序。

      关于UAC的信息,参考下列主题:

 

 

 

 

 

 

 

 

 

 

1.6.1 开发需要管理员特权的应用程序 Developing Application that Require Administrator Privilege

      开发一个应用程序,使它以运行标准用户身份运行,但是执行要求管理员特权的操作是可能的。

      有几个模型可以实现这一点。

 

 

 

 

 

 

 

 

 

 

 

 

1.6.1.1 管理员代理模型 Administrator Broker Model

      在管理员代理模型中,应用程序被一分为二。一个程序以标准用户身份运行,另一个以管理员身份运行。

      使用一个应用程序清单(manifest),标记标准用户程序的asInvoke为requestedExecutionLevel,标记管理员程序的reqireAdministrator为requestedExecutionLevel。用户首先加载标准用户程序。当用户尝试执行一个要求完整管理员权限的访问令牌时,标准用户程序调用ShellExecute函数加载那个管理员身份运行的程序。ShelExecute函数会在以用户的完整管理员访问令牌运行应用程序之前提示用户提升权限。在此之后,管理员程序才可以执行要求管理员特权的任务。

      管理员程序并不是完全独立于标准用户程序的。管理员程序可以允许和标准用户程序做进程间通信。然而,这样的通信受限于默认的强制诚信策略。关于强制诚信考虑的信息,参考设计运行在低诚信层级的应用程序

      下面的资料对管理员代理模型可能有用:

  • 开发向导。当一个硬件向导判断一个要求的驱动没有在计算机上安装,或者位于在企业的允许范围之外,它会调用一个提升权限能力的应用程序把驱动移动到计算机商店。
  • Autorun.exe调用Setup.exe。当一个用户从CD运行软件,作为标准用户运行的Autorun.exe启动Setup.exe安装软件到计算机上,而这个Setup.exe是以管理员身份运行的。

      下面是使用管理员代理模型的弊端:

  • 在应用程序之间转换会让用户感到迷惑。很难让用户明白为什么一个新的应用程序出现在它的屏幕上。
  • 很难在两个程序之间传递状态信息。比如,你不使用这个模型在标准用户控制面板(CPL)和它的管理员对应部分之间传递状态,而允许同样的CPL拥有管理员和标准用户的功能。标准用户CPL就需要把它的状态存放在某个地方。
  • 在两个程序之间分割功能会有很多复制代码。

相关主题

1.6.1 开发需要管理员特权的应用程序

1.6.1.2 操作系统服务模型

1.6.1.3 提升任务模型

1.6.1.4 管理员COM对象模型

 

1.6.1.2 操作系统服务模型 Operating System Service Model

      在操作系统服务模型中,一个以标准用户身份运行的应用程序通过远程过程调用RPC方式与以系统级别运行的服务进行通信。

      标准用户应用程序在其程序清单中的asInvoker被标记为requestedExecuteLevel。要执行需要管理员特权的操作,标准用户应用程序标记请求为某个服务。

      使用操作系统服务模型的程序是要管理影响操作系统的应用程序的,比如反病毒软件或者其他有缺点的软件和间谍软件。标准用户程序允许登录用户控制服务的某些方面。服务程序负责分辨哪些操作是标准用户程序的。例如,反病毒服务可能允许标准用户启动对系统的扫描,但是可能不允许标准用户禁用实时病毒检查。

      使用操作系统服务模型的主要好处是不需要提升权限请求。

      使用操作系统服务模型的一个缺点是运行在系统上的服务会比一个任务占用更多的资源,并且普通用户不能停用服务。那样的话,可以考虑使用 1.6.1.3 提升任务模型。

      要实现操作系统服务模型,要创建一个标准用户客户端程序,和一个操作系统服务程序。并在安装应用程序的时候在操作系统中安装这个服务。

相关主题

1.6.1 开发需要管理员特权的应用程序

1.6.1.1 管理员代理模型

1.6.1.3 提升任务模型

1.6.1.4 管理员COM对象模型

1.6.1.3 提升任务模型 Elevated Task Model

      在提升任务模型中,通过启动一个计划任务,可以让一个以标准用户身份运行的程序执行要求管理员权限的操作。

      Windows Server 2003和Windows XP:不支持提升任务模型。

      任务不会像服务那样消耗操作系统资源,并且任务在执行完之后会自动关闭。除非必须考虑到向下兼容早期的操作系统,否则可以考虑用这个代替操作系统服务模型

      要使用任务来为标准用户执行管理员特权操作,需要满足一下几点条件:

  • 任务必须设置为以系统级别运行。
  • 与该任务相关的安全描述符必须确认允许标准用户启动任务。
  • 必须运行任务计划服务

      关于如何创建和启动任务的信息,参考任务计划

相关主题

1.6.1 开发需要管理员特权的应用程序

1.6.1.1 管理员代理模型

1.6.1.2 操作系统服务模型

1.6.1.4 管理员COM对象模型

1.6.1.4 管理员COM对象模型 Administrator COM Object Model

      在管理员COM对象模型中,通过创建一个提升权限的组合对象模型对象,使得一个标准用户可以执行要求管理员特权的操作。关于创建一个提升权限的COM对象,参考COM提升标识

      使用管理员COM对象模型的缺点是每次一个特权呢操作执行的时候都会提醒用户。

      任何用户可以控制的COM接口都必须由COM对象自身暴露。否则,一个没有特权的进程可能导致提升的COM对象在未经提示的情况下执行特权操作。

相关主题

1.6.1 开发需要管理员特权的应用程序

1.6.1.1 管理员代理模型

1.6.1.2 操作系统服务模型

1.6.1.3 提升任务模型

 

 

2. 使用C++授权  Using Authorization in C++

 

      你可以使用授权管理API来控制对程序资源的访问。

      如果你有一个基于访问控制列表ACL的访问控制解决方案,并且想避免把这种解决方案转换为授权管理,你可以继续使用ACLs来控制对资源的访问。关于使用ACLs控制对资源的访问详情,参考 2.4.4 用C++定义ACLs的许可,2.4.5 用C++根据一个SID创建一个客户上下文和2.4.6 用C++区分带ACLs的客户访问

      注意 对于大型企业,会在行政管理费用和性能之间做出平衡。随着安全资源和用户的增加,ACL的管理会变得很复杂。因为所有要求的关于访问权限的信息会被分配到安全资源上,所有性能不会受影响。授权管理的性能受规模的影响。

      关于其他授权任务的信息,参考 2.4用C++支持授权任务。

      

 

 

 

 

 

 

 

 

 

2.1 用C++定义许可 Defining Permission in C++

      在授权管理中,你可以通过创建一个授权策略存储来定义哪一个用户可以访问哪些应用程序资源。

      关于使用ACL定义许可的详情,可以参考2.4.4 用C++定义ACLs的许可

      为定义访问许可:

1. 创建定义的授权策略的存储:2.4.1 使用C++创建授权策略存储

2. 为指定的应用程序在授权策略存储中创建段:2.4.1.2 用C++创建应用程序对象

3. 定义应用程序对访问和修改资源的实现的操作:2.4.1.3 用C++定义操作

4. 把操作打包到用户想要执行的高级任务中:2.4.1.4 用C++把操作打包到任务

5. 定义由组构成的任务的角色:2.4.1.5 用C++把任务打包到角色中

      一个赋予角色的用户拥有执行那个角色中任何任务的许可。

6. 创建脚本在运行时验证对任务的访问:2.4.3 用C++写的商业逻辑验证访问

      这一步是可选的。

7. 定义用户组:2.4.1.6 用C++定义用户组

      可以把这些组设置给角色以判断它们可以执行哪些任务。

8. 为用户组添加用户:2.4.1.7 用C++把用户添加到应用程序组

 

2.2 使用C++检查客户端对请求资源的访问  Verifying Client Access to a Requested Resource in C++

      调用IAzClientContext接口中的AccessCheck方法,检查客户端是否拥有对一个或多个操作的访问权。一个客户端可能拥有一个或多个角色成员,一个操作可能被赋值给一个或多个任务,所以授权管理会检查所有的角色和任务。如果客户端中的任何角色包含了任何一个操作的任务,那么对这个操作的访问就是允许的。

      为了检查属于客户端的单个角色,要设置IAzClientContext接口中的RoleForAccessCheck属性。

      当你为访问检查初始化授权策略的时候,你必须设置IAzAuthorizationStore::Initilize方法的lFlag参数为0。

      下面的例子演示了如何检查一个客户端对一个操作的访问权限。这个例子假定了C盘根目录下有一个名为MyStore.xml的XML策略存储,这个策略存储包含了一个名为Expense的应用程序和一个名为UseFormControl的操作,变量hToken包含了一个可用的客户端令牌。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.3 用C++授权许可定义  Delegating the Defining of Permissions in C++

      存放在活动目录中的授权策略存储支持管理托管。可以托管管理到存储中的用户和组,或者范围层级。

      在每一个层级,都有一个管理员和读者列表。存储、应用程序、或者范围的管理员可以在托管层级读取和修改策略存储。读者可以在托管层级读取策略存储但是不能修改存储。

      必须作为包含那个应用的策略存储的授权用户添加这个应用的用户或者组(就是说或者是应用的管理员,或者是应用的读者)。同样地,必须作为包含那个范围的应用的授权用户包含这个范围内的用户和组(也就是管理员或者读者)。

      例如,要授权某个范围的管理,首先,调用IAzAuthorizatoinStore::AddDelegatedPolicyUser方法把用户和组添加到包含那个范围的存储的授权用户列表。然后,调用IAzScope::AddDelegatedPolicyUser添加用户和组到包含这个范围的应用的授权用户。最后,调用IAzScope::AddPolicyAdministrator方法添加用户和组到这个范围的管理员列表。

      基于XML策略存储不支持任何层级的授权。

      如果某个范围包含了任务定义,而这个定义又包含授权规则或者包含授权规则的角色定义,那么不能授权存储在活动目录中的授权存储中的这个范围。

      下面的例子说明了如何授权一个应用的管理。这个例子假定在指定的位置有一个活动目录授权策略存储,这个策略存储包含一个名叫Expense的应用,这个应用没有包含商业规则脚本的任务。

 

 

 

 

 

 

 

 

 

 

 

 

 

2.4 用C++支持授权任务  Supporting Tasks for Authorization in C++

      下列任务支持列于2 使用C++授权中的主要任务。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.4.1 使用C++创建授权策略存储 Creating an Authorization Policy Store in C++

      在安装一个应用之前或过程中创建一个授权策略。

      当你使用授权管理API创建授权策略时,参考下面的主题中提供的指令。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.4.1.1 用C++创建授权策略存储对象 Creating an Authorization Policy Store Object in C++

      一个授权策略存储包含关于一个应用的安全策略或者应用程序组的信息。这些信息包括应用程序、操作、任务、用户、和存储相关的用户组。当一个使用了授权管理的应用初始化时,它会从存储中加载这些信息。授权策略存储必须存放在可信任的系统上,因为这个系统上的管理员对这个存储拥有高度访问权限。

      授权管理支持把授权管理策略存储在活动目录中或者是如下所示的一个XML文件中。在授权管理API中,一个授权策略存储使用一个AzAuthorizationStore对象来表示。下面这个例子演示了如何为活动目录存储和XML文件存储创建一个AzAuthorizationStroe对象。

创建一个活动目录存储

      为了使用活动目录存储授权策略,这个域必须位于Windows Server 2003 域功能层。授权策略存储不能位于非域名上下文(也叫应用程序分区)。推荐把这个存储放在专门为授权策略存储创建的新组织单元下的Program Data容器中。也推荐把这个存储放在同应用服务相同的局域网内,这个服务运行使用这个存储的应用程序。

      下面的例子演示了如何创建一个AzAuthorizationStore对象,这个对象代表在活动目录中的一个授权策略存储。这个例子假设在名为authmanager.com的域中有一个名为Program Data的活动目录组织单元。

 

 

 

 

 

 

 

 

 

 

 

创建一个SQL服务存储

      授权管理支持创建一个基于Microsoft SQL Server的组织策略存储。要创建一个基于SQL Server的组织存储,可以使用一个MSSQL://开头的URL。这个URL必须包含一个有效的SQL连接字符串,一个数据库名,和授权策略存储的名字:MSSQL://ConnectionString/DatabaseName/PolicyStoreName.

      如果这个SQL Server实例不包含指定的授权管理数据库,授权管理会使用那个名字创建一个新的数据库。

      注意 连接SQL Server是不加密的,除非你明确地为连接安装SQL加密或者安装使用英特网协议安全性(IPsec)的网络流量加密工具。

      下面的例子演示了如何在SQL Server数据库中创建一个代表授权策略存储的AzAuthorizationStore对象。

 

 

 

 

 

 

 

 

 

 

创建一个XML存储

      授权管理支持用XML格式创建一个授权策略。XML存储可以位于应用程序运行的同一个计算机上,或者存储在远程计算机上。不支持直接编辑XML文件。使用授权管理MMC管理单元或者授权管理API来编辑策略存储。

      授权管理不支持授权一个XML策略存储的管理员。关于授权的更多信息,参考2.3 用C++授权许可定义。

      下面的例子演示了如何创建一个AzAuthorizationStore对象来表示XML文件中的一个授权策略。

      

 

 

 

 

 

 

 

 

 

 

2.4.1.2 用C++创建应用程序对象  Creating an Application Object in C++

      一个授权策略存储包含一个或多个应用的授权策略信息。对于每一个使用这个策略存储的应用程序,你必须创建一个IAzApplication对象并把它存储到策略存储中。

      下面的例子演示了如何创建一个代表应用程序的IAzApplication对象,以及如何添加这个IAzApplication对象到这个应用使用的授权策略存储中。这里例子假设在C盘根目录有一个名为MyStore.xml的XML策略存储。

 

 

 

 

 

 

 

 

 

 

 

2.4.1.3 用C++定义操作 Defining Operations in C++

      

 

2.4.1.4 用C++把操作打包到任务 Grouping Operations into Tasks in C++

      

 

2.4.1.5 用C++把任务打包到角色 Grouping Tasks into Roles in C++

      

 

2.4.1.6 用C++定义用户组 Defining Groups of Users in C++

      

 

2.4.1.7 用C++把用户添加到应用程序组 Adding Users to an Application Group in C++

      

 

2.4.2 用C++建立一个带有授权管理的客户上下文 Establishing a Client Context with Authorization Manager in C++

      

 

2.4.3 用C++写的商业逻辑验证访问 Qualifying Access with Business Logic in C++

 

2.4.4 用C++定义ACLs的许可 Defining Permissions with ACLs in C++

      

 

2.4.4.1 用C++修改一个对象的ACLs Modifying the ACLs of an Object in C++

      

 

2.4.4.2 用C++创建一个新对象的安全描述符 

      

 

2.4.4.3 用C++控制子对象的创建 

      

 

2.4.4.4 用C++打开和关闭特权

      

 

2.4.5 用C++根据一个SID创建一个客户上下文 Establishing a Client Context from a SID in C++

      

 

2.4.5.1 用C++在一个访问标记里搜索SID 

      

 

2.4.5.2 用C++把一个二进制的SID转为字符串类型

      

 

2.4.6 用C++区分带ACLs的客户访问  Verifying Client Access with ACLs in C++

      

 

2.4.7 用C++寻找一个文件对象的拥有者 Finding the Owner of a File Object in C++

      

 

2.4.8 用C++获取对象拥有者 Taking Object Ownership in C++

      

 

3. 用脚本使用授权

3.1 用脚本定义许可

3.2 用脚本区分对一个请求资源的客户访问

3.3 用脚本委任许可定义

 

3.4 用脚本支持授权任务

3.4.1 用脚本创建授权策略存储

3.4.1.1 用脚本创建授权策略存储对象

3.4.1.2 用脚本创建应用程序对象

3.4.1.3 用脚本定义操作集

3.4.1.4 用脚本把操作打包到任务

3.4.1.5 用脚本把任务打包到角色

3.4.1.6 用脚本定义用户组

 

3.4.1.7 用脚本添加用户到一个应用程序组

3.4.2 用脚本创建客户上下文

 

3.4.3 用脚本赋予“用户”商业逻辑的访问

 

4. 使用授权API

4.1 初始化一个客户上下文

4.2 查询客户上下文

4.3 添加一个SID到客户上下文

4.4 使用授权API检查访问

 

4.5 缓存访问检查

 

5. 授权参考文档(detail从略)

5.1 授权常量

5.2 授权数据类型

5.3 授权枚举

5.4 授权函数 (这个很重要,要学会查)

5.5 授权接口

5.6 授权对象

 

5.7 授权结构体

 

6. Microsoft.Interop.Security.AzRoles (detail从略)

 

 

附录

Security Glossary