只要系统中有所动作,主体(可以是代表用户或服务执行操作的进程或线程)都会在对象上执行一些操作。比较常见的对象有文件、目录和注册表项。Windows 的基本安全机制包括使用可信的系统组件在执行操作之前检查权限和权利 (AccessCheck)。因此,可以通过设置权限和权利管理系统行为。因为在尚未理解权限和权利工作原理的情况下可能无法正确设置权限,所以我将首先介绍对象的安全设置及其处理方式,然后介绍如何为它们设置值。
在深入探讨技术细节之前,让我们先使用Windows 访问控制列表 (ACL) GUI 看看 Windows Server 2008 中的系统驱动器根目录权限。如果打开 Windows 资源管理器,选择“安全”选项卡、右键单击“本地磁盘 (C:)”,并选择“属性”,我们会看到管理员具备xx控制权限。如果单击“组或用户名”下的 SYSTEM,将会看见 SYSTEM 同样具有xx控制权限。当单击“组或用户名”下的 Users 时,权限情况则比较复杂:图1 中系统上的用户组具备 Read & Execute、List、Read 等权限。单击“高级”按钮将显示出与该用户组相关联的权限的详细视图(请参阅图2)。 图1 本地磁盘C 的用户权限 图2 C盘的用户权限高级视图 用户组的成员可以在系统驱动器根目录下创建文件夹并向文件添加数据。如果单击“编辑”按钮,您将看到另一项对子文件夹的“特殊”授权,如图3 所示。此操作需要管理员权限。 图3 用户特殊权利的编辑视图 您可以看到在 Windows Server 2008 中,普通用户默认可以在系统驱动器的根目录创建子文件夹,并向这些文件夹添加内容。为 Windows Server 2008 中用户组的成员提供该功能的原因是某些第三方软件假定存在这些权限,而 Microsoft 不想破坏应用程序的兼容性。 现在让我们开始讨论这些问题涉及的技术,并了解这些权限在用户所能看见的 GUI 界面之下的工作原理。在 Windows 中所有命名的对象都具有安全描述符,它提供有关其所有者的信息,并列出哪些用户和主体具有特定权限。描述符还可以指定必须在系统事件日志中记录哪些对象访问权限。 允许哪些主体(用户、进程等)操作某个对象或资源的信息在称为 ACL 的数据结构中指定。ACL 枚举谁(哪个主体)对具体对象具有哪类访问权限。自由 ACL (DACL) 是 ACL 的一种,在这种类型中对象的所有者可以更改权限。无论何时访问对象,都会将安全描述符与主体的权限进行比较以检验是否允许所请求的访问。 请注意:Windows 还支持针对对象的系统 ACL (SACL),并已在许多版本中使用 SACL 设置建立了需要记录到审核日志的事件。在 Windows Server 2008 和 Windows Vista 中,SACL 已扩展至能够携带完整性级别信息。 该完整性标签将用于建立“低级”标签,用它标记 LowRights Internet Explorer 中的 Internet Explorer 进程。“系统”和“高级”标签用于保护重要的系统资源。Windows 消息泵可以根据消息的完整性级别过滤消息。例如,中级进程不会接收低级进程发送的消息,而高级进程不会接收来自低级或中级进程的消息。 此时,完整性级别保护起到的是缓解的作用,而不是真正用于安全保护的安全屏障。在后续版本中,随着它逐渐成为真正的安全屏障,它的作用会大大加强。 与其它现代操作系统一样,Windows 依靠 DACL 进行常规访问控制决策。此处我将重点介绍 DACL。系统要决定是否允许某个主体对某个对象执行操作需要检查以下几项内容:主体的权限、主体的令牌,以及对象的安全描述符。对象的二进制安全描述符将随主体的令牌一起传递给 AccessCheck 例程。随后将准备所请求的访问掩码位向量,该向量代表访问权限检查成功所必须具备的访问权利。该向量将随主体的安全描述符一同传递给 AccessCheck 例程,然后由该例程根据所请求的访问和对象的 DACL 检查用户的安全令牌并考量主体权限(通常基于角色或成员关系,例如管理员)。 如果主体的权限满意所请求的访问,则授予访问权限。否则将按顺序检查 DACL 访问控制条目 (ACE)。一旦安全系统能够证明允许所有请求的访问组件或拒绝其中任何请求,它将相应返回成功或失败。 因此,ACE 的 DACL 列表应该按照适当的顺序排序。标准(规范)的排序应当是首先安排显式拒绝,然后是显式允许、一般(组)拒绝和组允许。如果不使用规范排序可能会导致预想不到的允许或拒绝。 对象安全描述符 虽然安全描述符是二进制数据结构,但它需要依赖安全描述符字符串格式提供便于用户阅读的文本格式。字符串格式的安全描述符是以 null 结尾的字符串,它包含指明以下四个主要组件的令牌:所有者 (O:)、主要组 (G:)、DACL (D:) 和 SACL (S:),如图4 所示。 图4 安全描述符 安全描述符 (SID) 通过结构化提供解析信息,并包含 96 位随机信息(并有可能包含 32 位序列计数器)以作为所有者的{wy}标识符。string_aces(以字符串格式表示的 ACE)是 DACL 中显式授予或拒绝权限和 SACL 中设置策略的结构。每个 string_ace 都包含在圆括号当中并采用以下结构:
只有那些正常访问相关对象所必需的权限必须存在。通常,安全描述符将省略 owner_sid 和 group_sid。如果在创建时未明确指定,那么安全描述符的所有者字段将设置为调用对象创建的主体的 SID。组字段设置为主体安全令牌的主要组。如果不需要审核对象或设置完整性标签,则不存在 SACL。 在string_aces 中,只包含那些必要的字段(最小集合为 ace_type、权利和对象,通常为 account_sid)。一般不包含 object_guid 和 inherit_object_guid。系统将按从前到后的顺序解析 ACE,直到授予或拒绝访问权限为止。因此,ACE 的顺序很重要。“拒绝权限”应该放置在“允许权限”之前。 不包含 ACE 的 ACL 是空 DACL。因为 ACE 授予特定主体对某个对象的访问权限,所以任何主体都无法访问具有空 DACL 的对象。没有 DACL 的对象称为 NULL DACL。具有 NULL DACL 的对象没有安全性,任何人都可以xx控制这种对象。因此,请不要设置空 DACL 或 NULL DACL。 现在我们有必要看看安全描述符的实际内容。下面是 Windows Server 2008 系统驱动器根目录的安全描述符(请注意 cacls 是用于检查和设置 ACL 的早期命令行例程,现已由 icacls 代替。遗憾的是,icacls 不支持使用命令行开关输出以标准安全描述符定义语言 (SDDL) 表示的结果,在 cacls 中该开关为 /S 标志):
根据我们已经了解的有关安全描述符的知识,您可以从开头的“D:”看出尚未声明所有者关系或组成员关系,而且该描述符是 DACL。该 DACL 是受保护的:已经设置了“P”和 Windows NT 5.0 继承标记。随后是一组需要进行解释的 ace_strings。 理解安全描述符 string_aces 回想一下前面讲述的 string_aces 格式。图5 中定义了有效的 ace_types,图6 中定义了有效的 ace_flags。用于继承的 ace_flags 是 ACE 继承的决定因素。 图5 有效的 ace_types 图6 有效的 ace_flags ACE 权利由字符串表明,该字符串指出 ACE 控制的访问权利。它可以是访问权利的十六进制字符串表示(例如“0x7800003F”),也可以是连续的 Rights 字符串(例如“CCLCSWLOCRRC”),稍后我将介绍后面这种格式。十六进制表示及其各个数位的值如图7所示。 图7 ACL 访问掩码 系统对所有对象使用一种 ACE 权利位图表示。对不同的对象来说,并不是所有的位都有意义。只应用那些适用于某个对象的权利。标准权利是对所有安全对象都通用的权限。泛型权利是为各种对象指定相似类型权利的简便方法。泛型权利的规范映射为一组适当的具体权限集合。当指定 SACL 时,完整性标签也将使用 ACE 权利字段进行编码。图8 中列出了各种对象的可用权利。 图8 泛型权利 有许多大致等同的权利映射在使用时并无区别。xx控制 (FC) 等同于 Generic_All (GA)。对于文件系统,File All (FA) 是适用的xx控制声明。Key All (KA) 是适用于注册表的xx控制声明。泛型声明常用于更适合声明的地方,但会根据需要映射为适当的文件系统或注册表项声明。SDDL 表达式常常混合这些术语,因此您需要了解等同的术语。 标准权利和特定权利 许多对象都可以分配权利。除文件和目录外,还有注册表项、进程、桌面等。要查看完整的列表,请参阅图 A 到图 J。我们将会讨论文件系统和注册表的权限,图9和图10中提供了这些对象的特定权利。 图9 特定文件权利 图10 特定注册表权利 完整性标签及其用法 前面提到过,如果存在完整性标签,则它将存储在对象的 SACL 中。对象隐含具有中级完整性,因此如果某个对象没有完整性标签,则它将具备中级完整性。同样地,如果安全令牌没有完整性标签,则它也将具备中级完整性。低级完整性标签用于标记低权利进程,例如低权利 Internet Explorer 及相关的非受信对象。“高级”和“系统”级别用于帮助将这些对象从中级和低级进程和对象中隔离出来。完整性标签如图11所示。 图11 完整性标签 Object_guid 和 inherit_object_guid Object_guid 和 inherit_object_guid 用于指定 Active Directory 中对象的安全性。不会使用它们来保护文件系统和注册表安全。ACE 字符串内 ace_type 字段中的“OA”和“OD”分别对应于对象允许和对象拒绝 ACE。在本例中,object_guid 持有正在请求权限的对象的 guid,而 inherit_object_guid 持有它所继承权限的那个对象的 guid。 ACE 结构中的 account_sid 字段代表将授予或拒绝 ACE 中所指定访问权利的安全主体。account_sid 字段可能持有某个 SID,它可能是对用户基本无用的长结构标识符,或者是某个通用帐户的简写“SID 字符串”标记。只要有利于增加系统的可读性,就可以使用通用帐户的 SID 字符串标记。通用或公认帐户及其 SID 字符串表如图 J 所示。 “所有者权利”的 OW 声明是 Windows Server 2008 和 Windows Vista 中新增的声明。在以前版本中,对象的创建者/所有者 (CO) 具有读控制 (RC) 标准权限和对该对象的 Write_DAC (WD) 权限,以便所有者能够设置该对象的安全性。如果用户是某个组的成员并创建了大量对象,这种方法会出现问题。如果该用户离开该组,他可能仍然会拥有对这些对象的控制,因为他是这些对象的所有者,所以可以获得这些对象的 RC 和 Write_DAC 权限。对 OW 所有者的 ACE 限制可以防止向所有者隐性授予 RC/WD 权限,除非在 ACL 中向任何其它相关 ACE 的所有者 ACE 显式授予这些权限。这种方法可以抑制以前版本中的安全隐患。 解释安全描述符 string_aces 对系统驱动器根目录运行 cacls 命令的输出如下:
为提高可读性对其进行解析后,结果如下:
这是一个受保护的 DACL,设置了流行文件系统的自动继承标志。受保护标志的含义是不会继承可继承的父权利;该 DACL 受到保护,不能继承父对象的权利。在本例中没有父项,因为它是根目录。 内置管理员和系统将得到文件(来自对象继承)和目录(来自容器继承,即 CI)可继承的 File All 权利。这意味着此 DACL 将递归授予根目录下所有文件和目录的 File All 权限—必须检查受保护 DACL 中的授权是{wy}的例外,那会禁止继承。CO 将获得根目录下所有文件和目录的 Generic_All 权限(由于仅继承标记),该权限将映射为 File All。 对内置用户的授权更为有趣。{dy}个 string_ace 将应用到根目录及其子目录中所有的文件和目录,授予 List、Read、ReadEA、Traverse、Execute、ReadAttr、ReadControl 和 Sync 权限。第二个 string_ace 授予在根目录及其子目录中 AddSubDir 的权限(由于 IO—仅继承标志),而第三个 string_ace 授予子目录的 AddFile 权限。这与您使用 Windows 资源管理器的 ACL 图形化界面查看这些权限时看到的一样。 Windows 资源保护 从 Windows Server 2008 和 Windows Vista 开始,组件将在其清单中声明所需的安全设置,该清单将由 Microsoft 代码签名根项进行签名。该清单指定 ACL 及与文件关联的其他权限。因此,当安装某个组件时,它将自带适当的安全设置。此外,系统管理员还可以使用 Windows 资源保护 (WRP) 防止操作系统文件受到意外损坏。WRP 依赖新的系统级别实体 Trusted Installer 拥有并管理系统文件和文件夹。 在 Windows Vista 中还增加了允许普通用户安装授权组件的便利功能。“超级用户”角色将不再需要,因此将删除包含“超级用户”SID 的 ACE 实例。“超级用户”组仍然存在,但会对组件清单进行扫描并删除所有 PU 权限授予实例。 让我们看看系统目录中有哪些新权限。同时这也是阅读并理解 SDDL 的一个良机:
“可信的安装程序”的 SID 是 S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464。使用 TI 作为简写,我们可以发现下面的内容:
通过解读,您可以看出这是受保护的 ACE,它使用 Windows NT 5.0 继承模型应用到 C:\Windows。 “可信的安装程序”对 C:\Windows 具有xx控制权限,并具有 C:\Windows 下所有子容器(由于是 CI,仅继承)的 Generic_All 权限。 系统和管理员拥有对 C:\Windows 的 Read、Write、Append、ReadEA、WriteEA、Execute、ReadAttr、WriteAttr、Del、RCtl 和 Sync 权限(等于 SDGRGWGX 权限)。这相当于 Generic_All 减去 Write_Owner 和 Write_DAC 权限;这表示除更改所有者和 ACL 以外,“管理员”和“系统”具有其他全部权限。“BA”和“SY”拥有对子文件和目录对象的 Generic_All 权限。 由于管理员能接管所有权,所以他仍然可以声明 WriteOwnership 权限并在任何情况下取得控制权。管理员和系统在安全方面不相上下。但由于有了该权限,管理员可以绕开 WRP ACL 控制。 CO 还拥有子文件和目录对象的 Generic_All 权限。内置用户拥有对 C:\Windows 的 Read、ReadEA、Execute、ReadAttr、RCtl 和 Sync 权限(等于 GRGX 权限),并拥有 C:\Windows 下子目录和文件的 GRGX 权限。 所有的系统文件和文件夹都包含受保护的 ACL,它们授予“可信的安装程序”xx控制权限。“可信的安装程序”对文件的控制不在系统根目录的声明中表述,而是在 Windows 组件的单独声明中表述。 设置安全文件系统权限 在了解文件系统 ACL 的工作原理和解读方法之后,让我们看看如何进行设置。如果正在安装某个应用程序,您应该将它安装到默认的 Program Files 位置。该位置的默认 ACL 将为管理员和本地系统提供xx控制权限,这并无不妥。 如果将应用程序安装到其它位置,或者允许用户选择喜欢的位置安装应用程序,那您将会遇到问题:其它驱动器和系统驱动器的非系统及非应用程序区域的默认 ACL 并不十分安全。在这种情况下,您必须使用受保护的适当 DACL 显式控制文件夹的 ACL。安装应用程序最简单安全的方法是复制 Program Files 文件夹的安全设置。如果选择不这么做,那您可以设置 DACL 使非管理员无法更改 DACL 和可执行文件的所有权,并使其无法在包含可执行文件的目录中写入、附加或删除文件。 如果您设置 DACL,基本规则是不希望管理员或其它用户执行由用户编写的代码。如果存在问题的文件夹位于受信区域(Windows、Program Files 等),则可假定它也是受信的,这时问题更为突出。这样做将允许管理员提升权限 (EoP) 并增加跨用户攻击的风险。因此,如果某位用户可以向文件夹写入文件,则其它用户和管理员应该不能执行这些文件。 乍一看似乎任何时候您都不应该允许用户向 Windows、System、Program Files 的文件夹中写入文件。但有许多充分的理由需要执行这类写入操作。最常见的是记录错误日志数据。如果可执行文件在用户凭据下运行并且需要记录错误,那它需要具备错误日志文件夹的写入/附加权限。(如果将错误记录到多用户系统中每个用户的位置,则需要将记录数据传遍整个系统,而不用与可执行文件相关联。应用程序和服务器通常写入共享文件夹或注册表项。)您会在注册表中发现相同的问题,使用用户权限运行的进程经常会把错误信息存储在特定的机器注册表项中。 请不要将用户可写的文件与可执行文件混放在一起。应该使用不同的目录存放必须信任的文件(例如可执行文件)和必须不被信任的文件(例如可能由不受信任的用户编写的任何文件)。为目录设置适当的 ACL—管理员控制可执行文件,而用户可以读取/执行但不能写入。注册表项和子项也适用相同的原则。 客户端和服务器的不同之处在于:服务器管理员假定比管理员用户具备更多的知识。服务器管理员知道他们必须拒绝执行来自系统非受信区域的代码。通过建立命名规范将数据文件与系统中的可执行文件隔离,您可以就可执行文件的可靠性为管理员提供指南—日志子目录并不可信,因此必须禁止用户创建或更改这些子目录,防止他们欺骗安全命名规则。 在客户端环境中,更容易诱骗管理员用户执行某些代码。对于此类天真的管理员来说,具备用户写入权限的目录必须禁止管理员具有执行特权,以防止用户在其中安装可执行文件并诱骗管理员用户运行这些文件而导致系统遭到破坏。例如,如果您的应用程序或服务需要存储以用户权限写入的日志信息,那您应该创建日志子目录以存储这些数据。管理员不应有该子目录的执行权限。可以在前面显式拒绝任何人执行文件,例如添加 D;OI;WP;;;WD。这样可以防止在允许用户写入或更改文件的目录中发生跨用户攻击。 在很多情况下可能需要用户能够共享数据(尽管我们不希望用户在共享区域共享和执行代码)。例如,家庭用户(或者他的照片查看应用程序)可能会创建类似 C:\Photos 这样的目录。该用户希望能够允许多个用户在此目录中写入文件并使其能够编辑该目录中的各种照片。 Windows Vista 中系统驱动器根目录的默认 ACL 支持这种应用。另一种常见的共享情况是用户希望在某个文件夹中放置数据供其它用户读取。只允许数据创建者删除或修改这些数据,但其他用户可以复制数据和编辑副本。这是一种共享读取方案,Windows Server 2008 的系统驱动器默认使用此方案。 现在考虑另外一种情形:您选择锁定系统驱动器,或具体而言,针对共享使用 ACL 设置文件夹。您需要选择适合这两种情况的 ACL,而不是常见方案。我们希望管理员能够管理对象,同时还希望防止因在这些文件夹中执行代码而出现安全问题(请注意:此处的 ACE 甚至会阻止所有者从这些文件夹执行代码)。 以下是共享读取 ACE:
以下是协作性 ACE:
请注意:两个ACL 都以拒绝所有人执行 ACE、对象继承(应用到文件)开始,从而防止用户系统和跨用户攻击。然后为管理员,系统(系统实际上不需要)和 CO 提供xx控制权限 (File All)。 对于“共享读取”方案来说,因为此授权在 CI 和目录方面的限制,经过验证的用户将获得 List、AddFile、AddSubDir、ReadEA、Traverse、ReadAttr、RCtl 和 Sync 权限,单独得到对所有文件的 Generic Read 权限。对于“协作”方案来说,经过验证的用户将获得文件和目录的 Delete、Generic Read 和 Generic Write 权限。 管理注册表及其权限 Windows 将许多状态信息存储在 Windows 注册表中。注册表数据以“配置单元”格式存储,数据存储在项和子项当中,可以将二者视为容器(子项不视为对象)。 用户特定数据存储在 Hive Key Users (HKEY_USERS) 的相应用户中。如您所料,这种数据大多可由用户写入。在任何会话内,HKey_Current_User (HKCU) 都将指向 HKEY_USERS 的适当部分。 系统和机器信息存储在 HKEY_LOCAL_MACHINE (HKLM) 配置单元中。HKLM 中包含的是各种系统服务的信息,其中大多数现在均使用本地服务或网络服务组的有限权限运行。服务和应用程序可以在其注册表项中存储状态信息。这些信息应该存储在子项(隶属服务项或服务项包含的项)当中。切勿通过 ACL 处理服务项,使该服务具有对其自身服务项的 SetKey 权限(或者 WDac 或 WOwn 权限,这些权限可能会导致此类攻击),因为这样会使该服务能够指向不同的可执行文件。此类错误可能导致服务主机遭到 EoP 攻击,因为服务控制管理器可能会在系统加载时也加载该服务所指向的可执行文件。 为 HKLM 设置 DACL 的一般原则是必须使用户不能写入或修改此数据、相关联的 ACL 和所有权。与设置系统区域中文件系统 DACL 的指导原则一样,使用用户权限或在受限环境中运行的应用程序或服务需要记录错误消息时,属于特例情况。对这种情况的指导原则与文件系统中解决类似问题的原则相似—为此类信息创建单独的项并为其设置适当的 ACL。因此,敏感信息可以通过 ACL 设置给受信主体(管理员、系统等),而日志数据也可在需要时允许写入。 您需要尽力避免的情况是用户修改受信任的参数(例如关闭反病毒或防间谍软件服务)或使用用户或管理员使用的工具篡改数据。假设当调用“记事本”时它会加载 C:\windows\notepad.exe。C:\windows 的默认 ACL 不允许攻击者修改此可执行文件。如果攻击者可以重写从“记事本”图标到其可执行文件的链接,则攻击者可以将该图标链接到其他文件(例如 C:\tools\load_rootkit.exe)并加载它。这样可以在加载 rootkit 之后再加载“记事本”,从而使用户感觉不到系统已经遭到破坏。 如果攻击者可以通过注册表驱动链接,那文件系统中保护性的 ACL 将起不到多大作用。您还可能受到从受限系统服务向其它系统服务发起的攻击。在 Windows Vista 和 Windows Server 2008 中,服务将按照其所需要的权限划分为不同的组。这种服务隔离技术提供的深度防御保护需要服务权限配置,这样服务(特别是跨服务组的服务)之间将无法互相篡改数据。 正如我们需要考虑防止用户添加或链接到恶意可执行文件一样,我们还必须防止服务更改其权限和功能。服务的 ChangeConf 权限必须限定给管理员、系统或可信的安装程序,因为该权限允许处理器更改服务的权限。 总结 Windows 提供了非常丰富的权限控制功能,它们可用于允许操作、阻止操作并提供对新威胁的深度防御。这一丰富的访问控制功能自然会令加大复杂性。 以下几项一般指导原则可以帮助您避免出现各种问题。例如,系统默认配置相对比较安全。您应该尽可能使用这些配置。如果将应用程序安装到 Program Files 以外的位置,请使用程序文件 ACL。在某些情况下,您可能希望限制一些默认权限,例如默认授予用户的驱动器权限;但请记住如果确实需要这么做,您应该准备好查找和处理潜在的应用程序兼容性问题。 最重要的指导原则是严禁管理员或系统帐户执行或通过指针指向用户能够写入或修改的代码。同样重要的是用户不能执行或通过指针指向另一个用户能够写入或修改的代码。这些指导原则适合本文中讨论的各种安全问题。如果您所做的更改都遵守这些指导原则,那您将可以避免大多数严重的安全问题。 有关访问控制组件的更多信息,请参阅 MSDN 中的“访问控制组件”。有关 ace_string 访问掩码组件的信息,请参阅 MSDN“ACCESS_MASK”文章,其中包含对文件、目录、注册表项和共享内容特殊权限的介绍。有关受限 SID 的其他信息,请参阅 MSDN“受限令牌”文章。 权利的完整列表
图A 标准权利 图B 文件和目录的特定权利 图C 文件映射和注册表的特定权限 图D 服务控制管理器和服务的特定权利 图E 进程和线程的特定权利 图F WindowStations 和桌面的特定权利 图G 符号链接和事件的特殊权利 图H 信号量和互斥体的特定权利 图I 管道和令牌的特定权利 图J 通用或公认的帐户及其SID字符串 John R. Michener 是Microsoft 的高级安全项目经理,Windows 软件保证团队的密码和权限专家,拥有20多年系统安全方面的经验。 |