再聊Windows的访问控制(Access Control)(二)

        上一篇介绍了Windows访问控制机制中的一个重要组成部分——访问令牌,今天再介绍一下安全描述符(Security Descriptor)。

安全描述符的结构
 

       安全描述符可被视作可保护对象的一个持久属性。每个可保护对象都有一个安全描述符,可能是由对象的创建者明确指定的,也可能是在创建时继承父对象或由系统赋予的默认安全标识符。
安全描述符用于保护可保护对象,其中包含了与可保护对象相关的安全信息:

  • 拥有该可保护对象的用户的SID(所有者SID)及其所属的主要组(Primary Group)的SID。
  • 一个自主访问控制列表(DACL, Discretionary Access Control List),其中规定了该可保护对象对特定用户和组允许及拒绝的访问权限。
  • 一个系统访问控制列表(SACL, System Access Control List),指定为哪些用户或组的什么访问操作生成审计记录。
  • 一组控制位,用于控制ACE的继承等方面的语义。
访问控制列表(ACL)


        安全描述符可以包含一个自主访问控制列表DACL和一个系统访问控制列表SACL,但这两个成分都不是必需的。DACL规定对特定用户或组允许或拒绝的访问权限,SACL控制系统如何为对对象的访问尝试生成审计记录。
        按照国际通行的计算机系统安全标准,Windows系统位于C2级别,该级别要求系统管理员必须能够审计安全相关事件,并且这些审计信息必须只有经过授权的管理员才能查阅。安全描述符的SACL就是为了支持这一要求而设置的。SACL中的ACE指定什么样的访问尝试会触发审计记录,ACE指定一个受信任实体,一组访问权限,以及一组标志用来指示系统是记录该组权限对应的成功的访问尝试,还是失败的访问尝试,还是两种都记录。要读写对象的SACL,线程必须有SE_SECURITY_NAME特权。

        访问控制列表中可能包含若干个访问控制项(ACE, Access Control Entry),也有可能一个也没有。每条ACE指定一组访问权限以及一个受信任实体(Trustee)的SID,规定对该受信任实体是允许还是拒绝这组访问权限规定的访问操作,亦或是对这些访问尝试生成审核记录。
        受信任实体可以是用户账户、组账户、登录会话等可被ACE实施访问控制的实体。用户账户除了指人类用户所使用的账户,还包括某些程序(如Windows服务)用来登录到系统所使用的账户;登录会话用于实施针对用户注销本次会话前的访问控制。

ACE

        ACE是ACL的组成元素。ACE控制或监视来自受信任实体对可保护对象的访问。在DACL中,每个ACE指定一个受信任实体的SID和一组访问权限,根据ACE类型来决定当该SID尝试这组访问权限相应的访问请求时是允许还是拒绝。在SACL中,也是每个ACE指定一个受信任实体的SID和一组访问权限,根据一组标志来决定当该SID尝试这组访问权限相应的访问请求时是记录成功的访问、失败的访问还是两者都记录。ACE的结构大致如下:

Windows系统共定义了六种ACE,其中三种适用于所有类型的可保护对象,叫“标准ACE(Standard ACE)”,另外三种叫“对象特定ACE(Object-specific ACE)”,适用于目录服务中的对象。

以下是三种标准ACE:

ACE类型 说明
访问拒绝ACE(Acess-denied ACE)

在DACL中规定就某些访问权限拒绝向指定受信任实体开放。采用以下数据结构(C定义):

typedef struct _ACCESS_DENIED_ACE{

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD SidStart;

} ACCESS_DENIED_ACE;

访问允许ACE(Access-allowed ACE)在DACL中规定就某些访问权限允许向指定受信任实体开放。采用以下数据结构(C定义):

typedef struct _ACCESS_ALLOWED_ACE{

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD SidStart;

} ACCESS_ALLOWED_ACE;

系统审计ACE(System-audit ACE)在SACL中规定在指定受信任实体尝试对可保护对象执行指定操作时生成审计记录。采用以下数据结构(C定义):

typedef struct _SYSTEM_AUDIT_ACE{

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD SidStart;

} SYSTEM_AUDIT_ACE;

以下是三种对象特定ACE:

ACE类型说明
访问拒绝对象ACE(Access-denied object ACE)

在DACL中拒绝某受信任实体访问对象的一个属性或属性集,或限定只允许一种类型的子对象继承该ACE。采用以下数据结构(C定义):

typedef struct _ACCESS_DENIED_OBJECT_ACE{

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD Flags;

GUID ObjectType;

GUID InheritedObjectType;

DWORD SidStart;

} ACCESS_DENIED_OBJECT_ACE;

访问允许对象ACE(Access_Allowed object ACE)

在DACL中允许某受信任实体访问对象的一个属性或属性集,或限定只允许一种类型的子对象继承该ACE。采用以下数据结构(C定义):

typedef struct _ACCESS_ALLOWED_OBJECT_ACE{

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD Flags;

GUID ObjectType;

GUID InheritedObjectType;

DWORD SidStart;

} ACCESS_ALLOWED_OBJECT_ACE;

系统审计对象ACE(System-audit object ACE)在SACL中,规定对该对象的一个属性或属性集的访问尝试生成审计记录,或限定只允许一种类型的子对象继承该ACE。

采用以下数据结构(C定义):

typedef struct _SYSTEM_AUDIT_OBJECT_ACE{

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD Flags;

GUID ObjectType;

GUID InheritedObjectType;

DWORD SidStart;

} SYSTEM_AUDIT_OBJECT_ACE;

(包含“对象特定ACE”的ACL必须使用ACL_REVISION_DS修订号。)

每种ACE都包含以下基本信息:

  • 本ACE所针对的受信任实体的SID
  • 一个访问掩码(Access Mask),规定了该ACE控制的访问权限
  • 一个表示该ACE类型的标志(在ACE_HEADER结构中)
  • 一组用来规定是否允许子对象或子容器对象继承该ACE的标志位(在ACE_HEADER结构中)

由表中ACE的数据结构定义可以发现,对象特定ACE多了两个GUID,一个是ObjectType,一个是InheritedObjectType。这两个数值扩展了ACE在目录服务中保护可保护对象的方式。

ObjectType可以表示以下信息之一:

  • 一种子对象的类型。用户控制所保护对象的子对象的创建,此时ObjectType表示该ACE只允许或拒绝对指定类型的子对象使用创建对象权限。
  • 一个属性或属性集。该ACE控制对指定属性或属性集的读写。
  • 一种扩展权限。该ACE控制与指定扩展权限相关联的操作。
  • 一种验证的写操作。该ACE控制执行特定的写操作的权限。这些验证的写入权限可在ACL编辑器中找到定义。

InheritedObjectType规定可以i继承该ACE的子对象的类型。

关于ACE的继承我们在下一篇再详细讨论。

如果没有指定这两个GUID,编程时推荐使用标准ACE结构,因为此时它有相同的语义,且更小、更高效。

安全描述符的创建

        当我们在系统界面(图形界面或字符界面)中或通过编程创建新的可保护对象时,就会有一个新的安全描述符作为该新建对象的持久属性被创建。其中内容的创建大致遵循以下逻辑形成。

DACL

SACL

所有者(Owner)

        新建可保护对象的所有者取自创建线程的主令牌或模拟令牌中的所有者SID(见上一篇中的描述)。对象的所有者隐含对该对象具有WRITE_DAC访问权限,这表示所有者有权修改对象的DACL,从而实现对该对象的访问控制。

        如果一个线程具有SE_TAKE_OWNERSHIP特权,那么它可以将某个对象的所有者设置为该线程的所属账户。如果一个线程具有SE_RESTORE_NAME特权,或拥有对某对象的WRITE_OWNER权限,那么它可以将该对象的所有者设置成任何有效的用户SID或组SID。

主组(Primary Group)

        新建可保护对象的主组可由创建者在创建时指定。如果没有指定,就将创建线程令牌中的默认主组作为新建对象的主组。

对访问检查(Access Check)过程的大致总结

        DACL中指定了一组受信任实体,对其规定允许还是拒绝其对受保护对象的特定访问。当线程尝试访问可保护对象时,系统就会检查DACL中的内容以确定是否允许该线程的访问。如果该对象没有DACL,就会允许任何受信任实体对其进行完全访问;如果该对象有DACL,但它是空的,里面没有任何ACE,那么该对象就会拒绝任何对它的访问——因为没有明确允许任何访问。如果DACL中的ACE向有限的用户和组提供了许可权限,系统会隐式地拒绝未涵盖在ACE指定范围的任何受信任实体的访问。从这个意义上来说,可以只采用“访问允许ACE”来实现访问控制,因为没有被ACE明确指定的受信任实体隐含地被系统拒绝了。但对于希望向一个组授予访问权限而又希望拒绝其中个别成员访问的情形,就要使用“访问拒绝ACE”了。在这种情况下,要将“访问拒绝ACE”放在“访问允许ACE”前面。

        系统在访问检查过程中会顺序地逐个检查DACL中的ACE,直到找到一个或多个ACE允许此次访问,或找到一个ACE拒绝此次访问请求的任何一种权限,从而拒绝访问。

        系统会将线程访问令牌中的SID与每个ACE中的SID进行比对。上一篇我们说到,访问令牌包含了用户和用户所属的组SID,以及一个登录会话SID。在访问检查过程中,系统会忽略掉没有启用(无SE_GROUP_ENABLED属性)的组SID。通常系统会使用线程的主令牌做访问检查,但如果线程是模拟其他用户身份运行,系统会使用线程的模拟令牌。系统逐个验证每条ACE,直到发生以下情形之一:

  • 被某ACE明确拒绝。该ACE拒绝了该线程所拥有的SID,或拒绝了本次访问请求的个别权限。
  • 遇到一个或多个访问允许ACE,它们的累积结果允许本次访问,即它们对该线程的SID是许可的,且它们所允许的各种权限累积起来可以满足本次请求。
  • 所有的ACE都已验证完毕,仍有至少一个请求的权限没有满足,系统隐式地拒绝此次访问。

        通过以上描述,我们可以察觉到系统授予用户的权限可能会由于DACL中ACE排序的变化而不同。为此,在Windows Server 2003、Windows XP系统中定义了一种ACE首选排序方案,该方案提供一个简单框架,可以确保访问拒绝ACE可以切实有效地对指定访问尝试做出拒绝反应。该首选排序方案概述如下:

  • 所有明确定义的ACE都要放在继承的ACE之前
  • 在所有明确定义的ACE中,访问拒绝ACE要放在访问允许ACE之前
  • 继承的ACE要按照继承顺序放置,即先放置继承自父对象的ACE,再放置继承自祖父对象的ACE,以此类推
  • 在继承的ACE的每个层级中,也要遵循把访问拒绝ACE放在访问允许ACE之前的原则

以下草图大致演示了这一方案:

明确定义的ACE访问拒绝ACE
访问允许ACE
继承的ACE继承自父对象访问拒绝ACE
访问允许ACE
继承自祖父对象访问拒绝ACE
访问允许ACE
... ...访问拒绝ACE
访问允许ACE

        还要补充一点,在每组访问允许ACE中,如果所针对的受信任实体呈层次结构,要按照影响范围由小及大的顺序排放。

下面简单举例演示一下访问检查地逻辑。

        图中线程A由用户1发起,线程B由用户2发起。用户同时是组A、组B和组C地成员,用户2属于组A。在可保护对象地DACL中定义了三个ACE,ACE1拒绝用户1的读、写、执行权限;ACE2允许组A的写权限;ACE3允许任何人的读、执行权限。

        线程A访问可保护对象时,系统首先读取ACE1,该ACE明确地针对用户1定义了拒绝动作,所以线程A地访问立即就被拒绝了,不用再继续验证ACE2和ACE3。由此可以看出ACE顺序的重要性。对于线程B,ACE1不适用,继续提取ACE2。ACE2允许组A的写权限,而用户2是组A成员,所以线程B有写权限,ACE3对所有人都开放读和执行权限,所以此时线程B也有了读和执行权限。

        本篇我们简要地介绍了安全描述符及其参与访问检查的机制。下一篇简单讨论一下ACE的继承话题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值