[Windows]Windows的访问控制模型

经过12月份的奋斗,OJ的判题程序已经初具雏形了,不过安全性仍然是一个令我非常头疼的问题,在这个问题上几乎耗了半个月的时间。虽然还没有找到完美的解决方法,但总算了解了Windows的安全性是如何工作的。下面分享一下在这方面的心得。

 

首先说一下Windows中的访问控制模型(Access Control Model),它是Windows安全性的基础构件。访问控制模型有两个主要的组成部分,访问令牌(Access Token)和安全描述符(Security Descriptor),它们分别是访问者和被访问者拥有的东西。通过访问令牌和安全描述符的内容,Windows可以确定持有令牌的访问者能否访问持有安全描述符的对象。

 

访问令牌是与特定的Windows账户关联的。当一个Windows账户登录的时候,系统会从内部数据库里读取该账户的信息,然后使用这些信息生成一个访问令牌。在该账户环境下启动的进程,都会获得这个令牌的一个副本,进程中的线程默认持有这个令牌。线程要想去访问某个对象,或者执行某些系统管理相关的操作时,Windows就会使用这个线程持有的令牌进行访问检查。

 

安全描述符是与被访问对象关联的,它含有这个对象所有者的SID,以及一个访问控制列表(ACL,Access Control List),访问控制列表又包括了DACL(Discretionary Access Control List)和SACL(System Access Control List)——目前还不知道这两个东西的确切翻译——其中,DACL是安全描述符中最重要的,它里面包含零个或多个访问控制项(ACE,Access Control Entry),每个访问控制项的内容描述了允许或拒绝特定账户对这个对象执行特定操作。至于SACL,它很少用到,主要是用于系统审计的,它的内容指定了当特定账户对这个对象执行特定操作时,记录到系统日志中。

 

好了,上面粗略地介绍了一下访问令牌和安全描述符,可是仍然没有讲到它们两者是如何协同工作的。要了解它们怎样保障Windows的安全性,需要进入它们的内部,看看里面有什么。

 

访问令牌中主要含有以下的内容:
当前登录账户的SID,也就是与令牌关联的账户的SID;
当前登录账户所属的账户组的SID列表;
受限制的SID(Restricted SID)列表;
当前登录账户以及它所属账户组的权限(Privileges)列表。

 

SID(Security Identity)是Windows中每个账户和账户组都有的一个标识符,平常我们看到的Administrator,Users等账户或者账户组在Windows内部是使用SID来标识的。例如S-1-5-21-1004336348-1275210071-725345543-1003就是一个完整的SID。每个SID在同一个系统中都是唯一的。

 

再来看看安全描述符中ACE的具体内容:
特定账户或者账户组的SID;
一个访问掩码(Access Mask),该掩码指定了具体的访问权限(Access Rights),也就是可以对该对象执行的操作;
一个位标记,指示了这个ACE的类型;
一组位标记,指示了安全描述符所属对象的子对象是否继承这个ACE。

 

所有的可访问对象都有三种ACE,分别是Access-denied ACE,Access-allowed ACE,System-audit ACE。Access-denied ACE用于拒绝账户访问,Access-allowed ACE用于允许账户访问,而System-audit ACE用于SACL中。

 

当一个线程尝试去访问一个对象时,系统会检查线程持有的令牌以及被访问对象的安全描述符中的DACL。如果安全描述符中不存在DACL,则系统会允许线程进行访问。

 

如果存在DACL,系统会顺序遍历DACL中的每个ACE,检查ACE中的SID在线程的令牌中是否存在。当满足以下条件时,遍历会终止:

 

某个Access-denied ACE中的SID在线程令牌中存在,而且该ACE中的权限与线程要求的权限相符,此时系统拒绝该线程访问对象。
某个Access-allowed ACE中的SID在线程令牌中存在,而且该ACE中的权限与线程要求的权限相符,此时系统允许线程访问对象。
所有ACE中的SID在线程令牌中均不存在,此时系统拒绝线程访问对象。

 

下图是转自MSDN的,Object对象的DACL中含有三个ACE,第一个ACE拒绝Andrew账户对Object进行读取,写入和执行操作;第二个ACE允许Group A账户组中的所有账户对Object进行写入操作;第三个ACE允许任何账户对Object进行读取和执行操作。

 

线程A试图访问Object,在遍历DACL的时候,遇到第一个ACE,满足上述的条件,遍历终止,线程A被拒绝访问Object,尽管线程A的访问令牌中含有Group A账户组的SID,并满足第二个ACE。同理,第三个ACE也没有被检查。对于线程B的分析是一样的,这里就不啰嗦了。可见ACE的排列顺序对线程能否访问对象是很重要的。

 

前面在介绍访问令牌的内容时,提到一个“受限制的SID列表”,对于这个东西,我曾经迷惑了很久,始终搞不懂它是干什么用的。经过一些实验之后,猜出了它的用途,尽管不一定对,这里简单说一下。

 

当一个访问令牌中含有受限制的SID列表时,系统在遍历ACE的时候只会与这些受限制的SID进行匹配,而忽略令牌中其余的SID,也就是相当于从访问令牌中删除了其它的SID。

 

另外,还有令牌中的权限列表,权限与对象访问无关,所以与安全描述符,SID等无关。当线程执行一些管理相关的操作时,系统会检查该线程的令牌中是否含有特定的权限,如果有,则允许线程执行该操作,否则拒绝。要查看完整的权限列表,可以运行gpedit.msc,然后定位到“计算机配置-Windows设置-安全设置-本地策略-用户权利指派”。

原文地址:https://www.cnblogs.com/zplutor/p/1639892.html