前言
《Windows Internal》是一本好书,以前读过这本书的第四版,而如今 Windows 10 都要正式发布了。在之前写《我所理解的马》这篇博客时,我发现自己无法回答自己提出的一些问题。原因很简单那,就是对 Microsoft 在 Windows 中新引入了一些机制不太清楚,所以重读了这本书第6本这一章,做了一些笔记。
下面的笔记一方面是对书中相关内容的记录,但更多的是还是自己对一些新引入的一些安全机制(如 UAC)的理解,还有就是对书上一些讲解不太清楚的地方(比如,Windows 的完整性机制)的解释及相关知识的补充。
另外,这本书第6版的的本章内容是可以免费得到的,只不过是英文的。
第 6 章 安全性
我们一直在学习 Windows 操作系统的安全机制,但好像从没思考过为什么操作系统需要安全机制或者操作系统的安全机制要保护的是什么?正所谓,不识庐山真面目,只缘身在此山中。应该说这个问题并不难回答。首先操作系统的安全机制要保护的是操作系统自身,防止用户无意间破坏系统,恶意程序破坏系统;其次操作系统的安全机制能够要保护一个用户的资源不会在这个用户没有对其他用户授予许可权的情况下被另一个用户访问。这两点就是操作系统的安全机制实现要达到终极目标。
另外,我们可以基于以上两点来比较下 Windows XP 和 Windows 7 在安全性方面的差距。
6.1 安全等级
Windows 满足的 TCSEC 标准 C2 安全等级的关键需求:
- 安全的登录设施
- 自主的访问控制
- 安全审计
- 它提供相应的能力来检测和记录安全相关的事件,或者任何想要创建、访问或删除系统资源的意图。
- 对象重用保护
Windows 满足的 TCSEC 标准 B 类安全等级中的两个需求:
- 可信路径功能
- 它防止特洛伊木马程序在用户登录的时候能够截取到用户的用户名称和口令。
- 可信设施管理
- 它要求针对各种管理功能有单独的账户角色作为支持。
这些安全标准一方面是 Windows 安全机制(或者所有操作系统的安全机制)实现的基础,另一方面其实也说明了 Windows 操作系统安全机制的核心机制和思想。
另外,没事时可以深入了解下这些安全标准。
6.2 安全系统组件
这小节,只能说看看就好,看不懂,记不住都没关系。
6.3 保护对象
对象保护和访问日志记录是自主访问控制和审计功能的本质所在。这句话说的很精髓。
关于 Windows 的完整性机制,现在感觉不太清楚的一点是它的使用情景。虽然书上说它用来实现同一用户内的隔离,但感觉还是很模糊。但我觉得,我们也可以先不用关心这点,而是先明白它是如何发挥作用的。关于这点很简单,就是在系统确定调用者对一个对象的访问权时,除了进行原来的自主访问检查外,首先还要进行强制完整性检查,并且只有在强制完整性检查和自主访问检查都通过的情况下,调用者才能获取对对象的访问权。在搞清楚这一点的基础上,在考虑它的使用情景。
访问检查
这小节涉及到的一些细节信息,即使不太明白,我们暂时也可以先不用关心。目前明白下面这一点就够了。
SRM 安全模型的本质是一个包含三项输入的等式。这三项输入是:一个线程的安全身份、该线程想要获得的对一个对象的访问权,以及该对象的安全设置。输出是“是”或“否”,表明了此安全模型是否授予该线程它所期望的访问权。
安全标示符(SID)
Windows 使用 SID 来标识系统中执行各种动作的实体,如用户、本地用户组、域中的用户组、本地计算机、域、域成员和服务。
完整性级别
下面这段话是 Windows 完整性机制实现的基本思想吧。
强制完整性控制(MIC,mandatory integrity contorl)机制通过把调用者关联到一个完整性级别,让 SRM 能够得到调用者自身属性的更详细信息。它给要访问的对象定义了一个完整性级别,从而指出了要访问该对象的调用者必须拥有的信任信息。
下面是关于 Windows 完整性机制的其他信息:
- 每个进程都在它的令牌中有一个完整性级别。
- 对象在它们的安全描述符中,也有一个完整性级别,保存在一个名为强制标签(mandatory label)的结构中。
- 所有的对象都有一个隐含的完整性级别,以避免要求用户手动指定。这个隐含的完整性级别是“中(medium)”级别。这样做,一方面是为了支持从老版本 Windows(它们的注册表键和文件都没有包含完整性级别信息)向新版本的迁移,另一方面也是为了方便应用程序开发人员。
- 什么是 强制策略(mandatory policy)?
感觉书上关于这部分的翻译太渣,下面是原文和我的翻译:
Apart from an integrity level, objects also have a mandatory policy, which defines the actual level of protection that’s applied based on the integrity-level check
除了拥有一个完整性级别,对象还有一个强制策略。强制策略定义了基于完整性级别检查的实际保护等级。
这段话的可以这样理解,完整性级别检查是要有目的的,这个目的就由强制策略定义。如果强制策略中没有定义相应的目的,就不会进行完整性检查。这就是为什么图6.6中中完整性级别的进程可以读取高完整性级别的普通对象,却不能读取高完整性级别的进程对象。就是因为目前用于普通对象的强制策略只有一个 No-Write-Up。而用于进程对象的除了 No-Write-Up 外,还有一个 No-Read-Up。
令牌
关于令牌我们没什么可以说的,唯一不熟悉的就是令牌中新加入的完整性等级和强制策略信息,不过这两个东西也没什么难理解的。
- SRM 使用一个令牌(或访问令牌)对象来标识一个进程或线程的安全环境。安全环境中包含的信息描述了与该进程或线程相关的账户、组和特权。令牌也包含了诸如会话 ID、完整性级别和 UAC 虚拟化状态之类的信息。
- 组 SID 能包含一个特殊的 SID,用来表示进程或线程的完整性级别。
- 令牌中的强制策略信息,它定义了 MIC(强制完整性控制)处理该令牌时将会有的行为。有两种策略:
- TOKEN_MANDATORY_NO_WRITE_UP,默认情况下启用,它在此令牌上设置了 No-Write-Up 策略,指示进程或线程将无法以写入方式来访问完整性级别更高的对象
- TOKEN_MANDATORY_NEW_PROCESS_MIN,默认情况下启用,指示 SRM 应该在它启动一个子进程时检查可执行映像的完整性级别,并计算出父进程和该文件对象的完整性级别之间的较小值,作为子进程的完整性级别。
模仿
模仿机制理解起来并不困难,不过,我觉得这也不是重点,重点应该是模仿机制的使用,在什么情景下使用,怎么用?模仿机制又有什么缺点?能做什么,不能做什么。所以,这小节关于这部分的内容才是我们该注意的。以后遇到使用模仿机制的实际需求时,可以参考下该小节。
受限制的令牌(restricted token)
不知道为什么要起这样一个名字。关于受限制的令牌现在唯一不太明白的一点就是受限制的 SID 的使用情景,虽然我们知道在自主访问检查算法中受限制的 SID 的处理方式,但我们还是感觉不理解它的使用情景。
已过滤的管理员令牌
已过滤的管理员令牌其实就是一个受限制的令牌。当然,这不是重点,重点是已过滤的管理员令牌的使用情景。它主要别用在 UAC 中,可以说它是 UAC 实现的基础。已过滤的管理员令牌有如下特性:
- 其完整性级别被设置为“中”
- 管理员 SID 和 管理员类的 SID 被标记为“仅仅拒绝”,而不是直接把这些组移除。注意这两者直接差别。
- 所有的特权都被移除,除了以下这些:Change Notify、Shutdown、Undock、Increase Working Set 和 Time Zone。
虚拟服务账户(virtual service account)
貌似也是新引入的安全机制,暂时先不关心吧。
安全描述符和访问控制
一个安全描述符由以下的属性构成:
- 版本号 创建此描述符的 SRM 安全模型的版本
- 标志 一些可选的修饰符,定义了该描述符的行为或特征。
- 所有者 SID 所有者的安全 ID
- 组 SID 该对象的主组的安全 ID(仅用于 POSIX)
- 自主访问控制列表(DACL) 规定了谁可以用什么方式访问该对象
- 系统访问控制列表(SACL) 规定了哪些用户的哪些操作应该被记录到安全审计日志中,以及对象的显式完整性级别。
在 DACL 中可以出现下面九种类型的 ACE,但我们暂时只关心前两种就好,第三种和第四种书上的意思应该是只用于活动目录对象,我们暂时不用关心,而且感觉书上的翻译也有点问题。
- 访问允许
- 访问拒绝
- 允许的-对象
- 拒绝的-对象
- 允许的回调
- 拒绝的回调
- 允许的对象回调
- 拒绝的对象回调
- 条件主张(conditional claim)
SACL 包含两种类型的 ACE:系统审计 ACE 和系统审计-对象 ACE。这些 ACE 指定在对象上由指定用户或组执行的那些操作应该被审计下来。
另外,其实无论是访问令牌还是安全描述符,理解这两小节最好的方法是结合 Windows 在 UI 界面中对这些东西的展示,比如 Windows 提供的文件或者目录的属性对话框中的安全页,这样这两小节讲的很多东西都跟实际的东西联系起来了,比如这小节讲到的 ACE 中的一些继承标志,如果我们不联系实际,可能完全想不到这些标志的实际意义的。
ACL 分配
没什么难理解的,里面主要也就是涉及到一些 ACE 继承的处理。
确定访问权
这里我们需要注意的点就是强制完整性检查,主要还是因为这是 Windows 新加入的东西,我们还是没那么熟悉。不过,这个东西理解起来也没什么困难的。就是系统在确认调用者请求的对对象的访问权时,先进行强制完整性检查,并且只有在强制完整性检查和自主访问检查都成功的情况下,才会授予调用者请求的对对象的访问权。
但我觉得书上对强制完整性检查的具体过程说的不太清楚,下面是我们自己的理解。
首先,依然从调用者(访问资源的线程)说起,从强制完整性检查的角度,我们需要哪些信息?结合前面的章节,一个进程或线程的访问令牌中包含如下和强制完整性检查有关的信息:
- 完整性级别
在令牌中是通过一个特殊的组 SID 表示的
- 强制策略
在令牌中是通过一个专门的域表示的,它定义了 MIC(强制完整性控制)处理该令牌时将会有的行为。
然后,我们在说说被访问的资源。依旧是结合前面的章节,一个对象的安全描述符中包含如下和强制完整性检查有关的信息:
- 完整性级别
对象在它们的安全描述符中,有一个完整性级别,保存在一个名为强制标签(mandatory label)的结构中。
- 强制策略
对象除了拥有一个完整性级别外,还有一个强制策略,在完整性级别检查的前提下,它定义了实际被应用的保护级别。
那系统依据这些信息进行判断的方式是什么呢?在回答这个问题之前,我们先看下图6.6。图6.6中中完整性级别的进程可以读取具有高完整性级别的普通对象,但不能读取高完整性级别的进程;中完整性的进程可以写入中完整性级别的普通对象和进程。为什么?其实由这就是强制完整性检查的检查方式决定的。
我觉得系统的检查方法可以这样描述:
- 首先系统需要先确定调用者请求的对象的访问权,是读,还是写,或者两者都有;
- 然后系统检查调用者的强制策略和对象的强制策略中有没有和调用者请求的对对象的访问权有关的强制策略。如果有,就进行下一步,如果没有,则整个强制完整性检查结束,并且最终的结果为“是”,接下来进行自主访问检查,只要自主访问检查成功,就授予调用者请求的对对象的访问权。这就是为什么会出现我们上面提到的图6.6中的情况。结合表6.4,我们可以看到,对于普通对象,只有一个针对写访问权的强制策略 No-Write-Up;但针对进程对象,还额外有一个针对读访问权的强制策略 No-Read-Up。
- 根据相应的完整性策略检查线程的完整性等级和对象的完整性等级,并输出最终的结果。
其实现在在看强制策略这个东西的意义,我觉得它可以这样理解。首先,它决定是否要对调用者请求的对对象的访问权进行强制完整性检查,比如图6.6中,中完整性级别的进程读高完整性级别的普通对象时,因为对象的强制策略中并没有用于普通对象的和读访问相关的强制性策略,所以根本就不会进行强制性完整性检查。其次,它决定了比较线程的完整性级别和对象的完整性级别的依据,比如对于 No-Write-Up 强制策略,它只有在线程的完整性级别大于等于进程的完整性级别时才授予线程对对象的写访问,但它也可以规定,在线程的完整性级别小于进程的完整性级别时才授予线程对对象的写访问。可以说,是否进行强制完整性检查,以及如何比较调用者的完整性级别和对象的完整性级别,完全是由强制策略决定的,强制策略才是 Windows 完整性级机制的核心。
下面是本节的一些基础知识。
有以下两种方法用于确定对一个对象的访问权:
- 强制完整性检查,它确定调用者的完整性级别是否足够高,以至于能够访问某资源;这一检查的根据是该资源自己的完整性级别,以及它的强制策略。
- 自主访问检查,它确定某个特定的用户账户对某个对象的访问权
当一个进程试图打开一个对象时,在内核的 SeAccessCheck 函数中,完整性检查是在标准的 Windows DACL 检查之前发生的,因为它执行起来更快,从而在某些情况下能快速地排除整个自主访问检查执行的必要性。
用户界面隔离(User Interface Privilege Isolation,UIPI)
这个东西主要是下面几个点:
- 阻止进程向其他完整性级别比它高的进程的窗口发送窗口消息,除了一些用于提供信息的消息之外
- 防止窗口钩子函数影响到完整性级别更好的进程的窗口
- 防止完整性级别较低的进程利用日志钩子(journal hook)函数来监视完整性级别更高的进程的行为。
然后书上对于下面这句话的翻译,也不太好。
UIPI also blocks window hooks from affecting the windows of higher integrity level processes so that a standard user process can’t log the keystrokes the user types into an administrative application,
自主访问检查
自主访问性检查主要涉及两个检查算法,这两个检查算法分别用于不同的情景。一个算法用于确定调用者可以获取的对象的最大访问权,主要用于调用者在请求对对象的访问权时,没有明确指定请求的访问权的情况;另外一个算法用于确定调用者请求的对对象的访问权是否允许,用于调用者在请求对对象的访问权时,明确指定了请求的访问权的情况。
下面是这小节提到的我们不太明白的访问权:
- 写-所有者(write-owner)访问权
- 写-DACL 访问权
- 读-控制(read-control)访问权
感觉这些东西倒还如不不翻译,感觉完全不知道在说什么,上面的这几个访问权可以参考 ACCESS_MASK,说的很清楚。
下面是关于这小节我们不太明白的点:
- OWNER_RIGHTS(所有者权限)SID
关于这东西的详细情况可以参考 新 ACL 改进 Windows Vista 的安全性,说的比书上详细的多。
然后关于书上对于下面这句话的翻译,我只能说完全看不懂。
If the caller is the owner of the object, the system looks for an OWNER_RIGHTS SID and uses that SID as the SID for the next steps.
下面我们讲讲对 OWNER_RIGHT SID 的理解。
首先,如果调用者是该对象的所有者,那就相当于调用者的令牌中多个一个具有 Enable 属性的 OWNER_RIGHTS SID,这个 OWNER_RIGTHS SID 和调用者令牌中的其他 SID 一样,在自主访问检查算法中扮演一样的角色;但有一点不同的是,如果对象的 DACL 中有一个关于 OWNER_RIGTHS 的 ACE,那么这个 ACE 授予调用者的权限将取代调用者作为该对象的所有者默认拥有的权限(read-control 和 write-dacl),这其实也是 OWNER-RIGHTS SID 存在的意义。
- 关于自主访问检查算法的最终结果受允许 ACE 和拒绝 ACE 的相对顺序的影响的理解
为什么会受到影响,是因为当系统在处理一个“访问-允许”的 ACE 时,如果这是线程请求的访问权并且线程请求的所有访问权限都已经别授予了,则访问检查就结束了。注意就结束了这一点,这意味这什么?这意味着即使对象在这个“访问-允许”的 ACE 之后,有一个“访问-拒绝”的 ACE 拒绝了用户请求的权限,系统也不会关心,因为已经结束了。同理,在系统处理一个“访问-拒绝”的 ACE 时,只要线程请求的任何一个访问权限属于这个这个 ACE 表示的拒绝的访问权限,则线程对该对象的访问请求别拒绝,访问检查也结束了。所以,书上才说检查算法的最终结果依赖于允许 ACE 和拒绝 ACE 的相对顺序。
- 受限制 SID
关于这个东西的作用,书上讲的还算清楚,但就是不知道这个东西用在什么情景下。
6.9 用户账户控制和虚拟化
- 什么叫用户账户控制(User Account Control ,UAC)?
我的理解是这样。它让那些以管理员账户登录系统的用户,不在默认具有管理员的权限,而是具有和普通用户账户差不多相同的权限,这样用户在做一些原来需要管理员权限再能做的操作时,系统就可以显式告诉用户,你做的这个操作需要管理员权限,是否要继续进行,防止用户意外的做一些危险的操作,给用户一个确认的机会;另外,在该用户下启动的应用程序也不再默认具有管理员权限,从而防止一些恶意的程序在用户不知道的情况下去做一些危害系统的操作,因为这些操作都需要管理员权限。
- UAC 的实现机制
核心机制就是在用户使用管理员账户登录时,除了创建一个管理员令牌外,还基于这个管理员令牌创建了一个已过滤的管理员令牌,这个已过滤的管理员令牌会去掉一些管理员权限和一些特权,然后这个已过滤的管理员令牌将作为用户的令牌,于是用户虽然使用管理员账户登录,但默认情况下并没有管理员权限。另外当用户要运行一些需要管理员权限或者做一些需要管理员权限的操作时,系统也能使用管理员令牌来创建这些进程,从而满足这些进程对管理员权限的需求。
文件系统和注册表虚拟化
应该说这两种机制本质上是为那些遗留的并且设计不太合理的应用程序而存在的。这原本是这些程序的开发者的问题,从开发的角度讲,微软完全可以不管,但微软还是从自身解决这个问题,而不是让开发者去修改他们的程序,为什么?因为这不仅仅是一个开发的问题吧。
- 使用情景
供那些本来不需要管理员权限就能运行,但因为自身设计不太合理(比如将一些配置文件或者用户数据写到需要管理员权限才能写的目录或者注册表键下)的应用程序使用,这样这些应用程序就可以在普通账户下运行了,而不是非要在管理员权限下才能成功运行。
- 实现机制
当一个应用层修改文件系统或者注册表的某个系统全局位置,并且该操作因为访问被拒绝而失败时,Windows 就把该操作重定向到一个针对每个用户的区域。当该应用程序从一个系统全局的位置读取时,Windows 首先检查用户区域中的数据,若没有找到,再允许从全局位置尝试读取。
文件虚拟化
不理解下面这句话什么意思?不过貌似不理解对我们对文件虚拟化的理解也没什么影响。
The Local component of the path highlights the fact that virtualized files don’t roam with the rest of the profile when the account has a roaming profile
注册表虚拟化
没什么说的
权限提升
以管理员权限运行
这小节主要是讲述了系统在运行一个需要管理员权限的程序时,所做的一些内部操作,一些相关细节以及这些操作和细节涉及的一些相关概念。
管理员批准模式(AAM,Admin Approval Mode)
“越过肩膀上方”权限提升(OTS,over-the-shoulder elevation)
应允提升(consent elevation)
Application Information Service,AIS
请求管理员权限
这小节主要讨论了这个问题:系统在运行一个应用程序时,怎么知道它需要管理员权限,或应用程序怎么告诉系统它运行时需要管理员权限。
自动权限提升
自动权限提升就是系统在运行某些进程时,不提示用户,直接以管理员权限创建该进程,不然每次运行需要管理员权限的进程都要提示用户,那系统的用户体验就会非常差,这就是 Windows Vista 之所以失败的原因之一。
另外,这个机制也是一些马自己过 UAC 的基础。基本就是使用这些系统会自动为其提升权限的进程去做一些需要管理员操作权限的操作,比如释放文件到系统目录,创建服务。
虽然说一些马还是能够利用这个机制做一些需要管理权限才能做的事,不过这个机制本身对能够进行自动权限提升的程序的要求已经很严格了,具体如下:
- 程序必须由 Windows 发行者签名(而不仅是由 Microsoft 签名),而且必须位于系统安全目录中
- 在程序文件的清单文件中通过 autoElevate 元素请求了自动权限提升或者位于 Windows 维护的一个内部列表中,该列表中的程序可以不使用 autoElevate 元素。
- Mmc.exe 不适用于上述两条要求,它还有自己额外的要求。
控制 UAC 的行为
不同的等级会决定系统在运行需要管理员权限的程序时的行为,然后系统的行为也会受到程序自身的性质影响,比如该程序是一个没有签名的程序,还是一个 Windows 自带的系统程序。
其实说了这么说,我觉得 UAC 对系统的安全性的提升并没有什么实质性的提高。
版权声明:本文为博主原创文章,未经博主允许不得转载。