windows 访问控制模型(二)之安全描述符


安全对象Securable Object是拥有SD的Windows的对象。

所有的被命名的Windows的对象都是安全对象。一些没有命名的对象是安全对象,如:进程和线程,也有安全描述符SD。安全对象Securable Object是拥有SD的Windows的对象。

在 Windows系统中,其是用一个安全描述符(Security Descriptors)的结构来保存其权限的设置信息,简称为SD,其在Windows SDK中的结构名是“SECURITY_DESCRIPTOR”。 下面看下SECURITY_DESCRIPTOR 的结构

kd> dt nt!_security_descriptor
   +0x000 Revision         : UChar
   +0x001 Sbz1             : UChar
   +0x002 Control          : Uint2B
   +0x004 Owner            : Ptr32 Void
   +0x008 Group            : Ptr32 Void
   +0x00c Sacl             : Ptr32 _ACL
   +0x010 Dacl             : Ptr32 _ACL


我们可以看到,去掉两个版本控制成员,一个安全描述符由五个成员组成:

自由访问控制列表(Dacl):这儿保存着对象的许可(允许谁访问对象,而拒绝谁)。
系统访问控制列表(Sacl):指定要对对象执行的审核的类型。如果发生了审核事件,会被存储到审核事件的日志中。
Owner:指定对象的所有者(一个 SID)。对象的所有者总是可以更改安全描述符,而不管其他人对访问的锁定。
Group:指定对象的主组(一个 SID)。Windows 通常忽略此参数(这是为了 POSIX 兼容性,但它现在已经退化了)。
Control:表现为一个 16 位整数的一组标志。

1、 安全标识符 SID
在钻研授权(authorization)的概念之前,我们先讨论一下安全标识符(SID)。我们人类喜欢拿用户名来指代一个用户(例如"Administrator"),而计算机需要用二进制数据来指代用户。它使用被称为 SID 的哈希值来辨识用户。当一个用户被创建时,计算机会为该用户创建一个 SID,从那时起,计算机将使用用户的 SID 而不是用户名来指代用户。要看你自己的 SID 列表,可以打开注册便编辑器并展开 HKEY_USERS 树(可以看到当前登录的用户们的 SID 列表)(译者注:原文如此。但译者自己的看法是可以看到本机所有用户的 SID)。可以使用 ConvertSidToStringSid() 把原始的 SID 结构转换为文本形式。文本的 SID 通常以 S-1-5-21- 开头,由至少三个用短线分开的值组成,这些值代表了修订版本、职权(authority)、子职权(sub authority)、ID 以及主组(primary groups)。

SID 也可以表示一个用户组、一台计算机、一个域乃至森林。Windows 维护着一个被称为周知 SID 的硬编码 SID 列表,它们代表了诸如 LocalSystem 或者NetworkService 这样的帐户。可以在 WELL_KNOWN_SID_TYPE 枚举中查看到这些 SID 的清单。

要把一个 SID 转换为用户名,需要调用 LookupAccountSid(),而 LookupAccountName() 则可以把用户名转换为 SID。不过,大多数的安全性函数既接受 SID 也接受用户名(实际上是接受一个 TRUSTEE 结构,该结构是一个用户名和 SID 的联合体)。


2、访问控制列表ACL

在 Windows NT 里,无论什么时候,当你要对一个对象执行操作(比如说读)时,要执行的操作会被编码为一个 32 位的整数(称为 ACCESS_MASK)。ACCESS_MASK 对于你试图创建的对象是特定的,如果你要读文件,那么 ACCESS_MASK 就应该是 FILE_GENERIC_READ。当你用请求 ACCESS_MASK 打开对象时,Windows 会取得你在线程令牌里的用户名并开始读取从安全描述符中取得的自由访问控制列表(Discretionary Aaccess Control List,DACL)。

DACL 可以被想象为一张表,其中有用户的 SID、ACCESS_MASK 以及访问类型。不过不要试图把它写成一个结构数组。如果你要分析 ACL 的话,可以使用低级 ACL 函数 GetAce()、 GetAclInformation() 以及其他的辅助函数。在 NT4 中,微软提供了 ACL 的一个示意,看起来就是由 SID、ACCESS_MASK 和类型组成的一个表(即 EXPLICIT_ACCESS 结构)。

/* Not valid C or C++ code */
struct ACE
{
    BYTE AceType;     /* can be allow/deny/audit/custom */
    BYTE AceFlags;    /* Inherited? */
    ...
    ACCESS_MASK Mask; /* Specifies the action */
    ...
    SID Sid;          /* associate with this user/group/... */
} ;

struct ACL
{
    BYTE AclRevision;
    ...
    WORD AceCount;                  /* number of ACEs */
    ...
    ACE AceList[this->AceCount];    /* An array of ACEs */
} ;

/* You can think of an ACL as an array of EXPLICIT_ACCESSes */
typedef struct _EXPLICIT_ACCESS
{
    DWORD grfAccessPermissions;     /* ACCESS_MASK */
    ACCESS_MODE grfAccessMode;      /* Allow/deny/audit/custom/... */
    DWORD grfInheritance;           /* Inherited? */
    TRUSTEE Trustee;                /* The SID */
} EXPLICIT_ACCESS, *PEXPLICIT_ACCESS;

如果 DACL 是一个表的话,则其中的每一行就是一个访问控制项(Access Control Entry)。当要执行操作时,Windows 就遍历此 ACE 列表来寻找指向你(你 就是线程令牌)的那一项。Windows 按照在 ACL 中的出现次序遍历 ACE。乍一看这与你的直觉、帮助文档甚至 MCP 的书中所述相悖("我认为 Windows 首先遍历所有的拒绝 ACE,然后才是允许 ACE。而现在,你竟然告诉我这是错的?")。实际上,我们都是对的。当 Windows 设置 DACL 时,它将访问控制项排序[^],拒绝 ACE 会优先于允许 ACE,从而访问控制模型也符合你的先前所学。

如果对低级函数进行调用,你就可以绕过排序而使 ACE 以你喜欢的任意顺序出现。Cygwin 工具使用这一技术来创建不排序的 DACL。不过这些 DACL 不能遵从访问控制规则。你也可以使用这些不正常的 ACL 来创建文件。

如果在 ACL 中没有找到你(你的令牌),则打开对象的函数就会失败(访问被拒绝)。如果你被找到了,Windows 会通过 ACE 来查看到底允许你做什么。如果 ACE 允许你打开此对象,则你被允许访问。如果这中间有什么事情失败了,则你会被拒绝访问。这是安全性最优方法的一个例子:"如果有什么错了,那么就安全地失败"。

现在,你已经被允许或者拒绝访问了,Windows 开始检查另一个 ACL - 系统访问控制列表(System Access Control List)。SACL 和 DACL 的不同在于 DACL 包含允许/拒绝项,而 SACL 包含审核项。SACL 告诉 Windows 哪些动作要向安全事件日志中记录(审核成功/失败)。除此之外,你可以将 SACL 和 DACL 同等对待。如果 Windows 找到一个 SACL (译者注:更准确地说应该是 SACL 中的某一个 ACE)说要审核此访问,则此次的访问企图会被写到事件日志里。

如果想知道一个 ACL 是否允许你访问某个对象,可以对那个对象使用 AccessCheck() API。

3、创建一个好的自由访问控制列表

在大多数情况下,Windows 已经为你确立了一个良好的自由访问控制列表。如果你遇到一个需要安全描述符或者 SECURITY_ATTRIBUTES 结构的 API,可以简单地为此参数传递 NULL。将 SECURITY_ATTRIBUTES 或者 SECURITY_DESCRIPTOR 传递为 NULL 会通知系统使用缺省的安全描述符。And that is probably what you were after.

如果需要更高级的安全性,则要你要确保创建了一个拥有填充过的 DACL 的安全描述符。如果你初始化了一个安全描述符,却忘记了为之构建一个关联的 DACL,你会得到一个 NULL DACL。Windows 将此 NULL DACL 对待为其具有以下 ACE:

"所有人:完全控制"("Everyone: Full control")

所以,Windows 会允许使用任何操作访问该对象。这是微软打破自己的最优方法的一个地方。当遇到了非预期的东西时,Windows 应该安全地失败,而在这种情况下它却不是。利用 NULL DACL,包括恶意软件在内的任何人都可以对对象做任何事情,包括设置一个具有威胁性的 rootkit 式 DACL 在内。出于这一原因,所以,不要创建具有 NULL DACL 的安全描述符。

设置一个 NULL DACL 并不等同于使用一个 NULL 安全描述符。将 NULL 作为安全描述符传递时,Windows 将使用一个缺省的安全描述符来替换它,而此安全描述符是安全的,允许对对象进行恰当的访问。设置一个 NULL DACL 意味着传递一个合法的安全描述符,只不过它的 Dacl 成员为 NULL。

出于同样的理由,你也许不希望设置一个没有包含任何访问控制项的 DACL。对于这样的 DACL,Windows 在遍历访问控制项时,第一次尝试就会失败,因此,它会拒绝任何操作。其结果就是一个完全不可访问的对象,这样的对象不会比一个不存在的对象好到哪儿去。如果你还想要访问一个对象,那你就必须有一个填充过的 DACL。

那么我们怎样才能构造一个自由访问控制列表呢?

考虑一下你想要谁能访问而又不想让谁访问,你的 DACL 是基于黑名单(全部都是拒绝 ACE)呢,还是基于白名单(全部都是允许 ACE)。如果你正要为安全描述符创建一个 ACL,最好还是使用白名单的方式。对象要持续多长时间?究竟是一个长时间运行的对象(就像长时间运行的进程中的应用程序互斥量那样),还是一个短时间运行对象(比如一个同步事件对象),或者是一个永久对象(例如一个文件)?

确定一个好的安全描述符取决于你计划对对象做些什么事情。如果你要保证一个内核对象的安全,你可能只需要同步、读以及读取其上的安全性。如果你要保证一个文件的安全,你可能会需要所有可用的访问模式(一整天)。

一般来说,对于永久对象至少需要有两个账户能访问它。第一个是 LocalSystem 账户,对一个永久对象来说,限制此账户的访问会导致很严重的问题;另一个则是对象的创建者或者当前的所有者。还需要考虑赋予管理员对此对象的完全控制。其他需要考虑的技术是仅允许用户的读访问和执行访问。当要删除文件时,他们必须自己添加 DELETE 权限,然后再删除。

对于短时间运行的对象来说,应该对对象的负责人赋予最少的权限。例如,如果你只希望从对象中读取并对之进行同步,那么就创建一个只允许读访问和同步访问的 DACL,在这种情况下你甚至可以对 LocalSystem 账户进行限制。

如果你的对象支持继承,除非你的文件在安全性方面有特殊要求,那么对它来讲不需要特殊的 DACL,你可以只是对它应用其父的 DACL,你可以通过在安全描述符的 Control 成员中设定自动继承标志来做到这一点。缺省的安全描述符会代你使用继承标志。

最后,如果仍然有疑问,去问管理员!

5、SDDL(Security Descriptor Definition Language)

安全描述符定义语言是使用文本来描绘安全描述符的一个尝试,使用的文本既可以让管理员明白也可以让计算机理解。在帮助文档中有 SDDL 格式的完整参考。

每个security descriptor 由4个部分组成 owner (O:), primary group (G:), DACL (D:), and SACL (S:).

O:owner_sid
G:group_sid
D:dacl_flags(string_ace1)(string_ace2)... (string_acen)
S:sacl_flags(string_ace1)(string_ace2)... (string_acen)
owner_sid
A SID string that identifies the object's owner.(一个标识对象所有者的SID字符串)

group_sid
A SID string that identifies the object's primary group.
string_ace
A string that describes an ACE in the security descriptor's DACL or SACL. For a description of the ACE string format, see ACE strings. Each ACE string is enclosed in parentheses (()).(DACL或SACL有固定格式的字符串)

(1)、SID string 

在安全描述符字符串中,SID字符串有两种形式,一个是 (S- R- I- S- S…)形式标识,另一种是在Sddl.h中定义的常量字符串

比如(具体参考msdn):

SID string Constant in Sddl.h Account alias and corresponding RID

"AN"

SDDL_ANONYMOUS

Anonymous logon. The corresponding RID is SECURITY_ANONYMOUS_LOGON_RID.

"AO"

SDDL_ACCOUNT_OPERATORS

Account operators. The corresponding RID is DOMAIN_ALIAS_RID_ACCOUNT_OPS.

"AU"

SDDL_AUTHENTICATED_USERS

Authenticated users. The corresponding RID is SECURITY_AUTHENTICATED_USER_RID.

"BA"

SDDL_BUILTIN_ADMINISTRATORS

Built-in administrators. The corresponding RID is DOMAIN_ALIAS_RID_ADMINS.

"BG"

SDDL_BUILTIN_GUESTS

Built-in guests. The corresponding RID is DOMAIN_ALIAS_RID_GUES

"SY"

SDDL_LOCAL_SYSTEM

Local system. The corresponding RID is SECURITY_LOCAL_SYSTEM_RID.

"WD"

SDDL_EVERYONE

Everyone. The corresponding RID is SECURITY_WORLD_RID.

 (2)、ACE格式如下:

ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid

ce_type
A string that indicates the value of the AceType member of the ACE_HEADER structure. The ACE type string can be one of the following strings defined in Sddl.h.

ACE type string Constant in Sddl.h AceType value
"A" SDDL_ACCESS_ALLOWED ACCESS_ALLOWED_ACE_TYPE
"D" SDDL_ACCESS_DENIED ACCESS_DENIED_ACE_TYPE
"OA" SDDL_OBJECT_ACCESS_ALLOWED ACCESS_ALLOWED_OBJECT_ACE_TYPE
"OD" SDDL_OBJECT_ACCESS_DENIED ACCESS_DENIED_OBJECT_ACE_TYPE
"AU" SDDL_AUDIT SYSTEM_AUDIT_ACE_TYPE
"AL" SDDL_ALARM SYSTEM_ALARM_ACE_TYPE
"OU" SDDL_OBJECT_AUDIT SYSTEM_AUDIT_OBJECT_ACE_TYPE
"OL" SDDL_OBJECT_ALARM SYSTEM_ALARM_OBJECT_ACE_TYPE
"ML" SDDL_MANDATORY_LABEL SYSTEM_MANDATORY_LABEL_ACE
Note   If ace_type is ACCESS_ALLOWED_OBJECT_ACE_TYPE and neither object_guid nor inherit_object_guid has a  GUID  specified, then ConvertStringSecurityDescriptorToSecurityDescriptor  converts ace_type to ACCESS_ALLOWED_ACE_TYPE.

ace_flags

A string that indicates the value of the AceFlags member of the ACE_HEADER structure. The ACE flags string can be a concatenation of the following strings defined in Sddl.h.

ACE flags string Constant in Sddl.h AceFlag value
"CI" SDDL_CONTAINER_INHERIT CONTAINER_INHERIT_ACE
"OI" SDDL_OBJECT_INHERIT OBJECT_INHERIT_ACE
"NP" SDDL_NO_PROPAGATE NO_PROPAGATE_INHERIT_ACE
"IO" SDDL_INHERIT_ONLY INHERIT_ONLY_ACE
"ID" SDDL_INHERITED INHERITED_ACE
"SA" SDDL_AUDIT_SUCCESS SUCCESSFUL_ACCESS_ACE_FLAG
"FA" SDDL_AUDIT_FAILURE FAILED_ACCESS_ACE_FLAG
rights

A string that indicates the access rights controlled by the ACE. This string can be a hexadecimal string representation of the access rights, such as "0x7800003F", or it can be a concatenation of the following strings.

Access rights string Constant in Sddl.h Access right value

Generic access rights

"GA" SDDL_GENERIC_ALL GENERIC_ALL
"GR" SDDL_GENERIC_READ GENERIC_READ
"GW" SDDL_GENERIC_WRITE GENERIC_WRITE
"GX" SDDL_GENERIC_EXECUTE GENERIC_EXECUTE

Standard access rights

"RC" SDDL_READ_CONTROL READ_CONTROL
"SD" SDDL_STANDARD_DELETE DELETE
"WD" SDDL_WRITE_DAC WRITE_DAC
"WO" SDDL_WRITE_OWNER WRITE_OWNER

Directory service object access rights

"RP" SDDL_READ_PROPERTY ADS_RIGHT_DS_READ_PROP
"WP" SDDL_WRITE_PROPERTY ADS_RIGHT_DS_WRITE_PROP
"CC" SDDL_CREATE_CHILD ADS_RIGHT_DS_CREATE_CHILD
"DC" SDDL_DELETE_CHILD ADS_RIGHT_DS_DELETE_CHILD
"LC" SDDL_LIST_CHILDREN ADS_RIGHT_ACTRL_DS_LIST
"SW" SDDL_SELF_WRITE ADS_RIGHT_DS_SELF
"LO" SDDL_LIST_OBJECT ADS_RIGHT_DS_LIST_OBJECT
"DT" SDDL_DELETE_TREE ADS_RIGHT_DS_DELETE_TREE
"CR" SDDL_CONTROL_ACCESS ADS_RIGHT_DS_CONTROL_ACCESS

File access rights

"FA" SDDL_FILE_ALL FILE_ALL_ACCESS
"FR" SDDL_FILE_READ FILE_GENERIC_READ
"FW" SDDL_FILE_WRITE FILE_GENERIC_WRITE
"FX" SDDL_FILE_EXECUTE FILE_GENERIC_EXECUTE

Registry key access rights

"KA" SDDL_KEY_ALL KEY_ALL_ACCESS
"KR" SDDL_KEY_READ KEY_READ
"KW" SDDL_KEY_WRITE KEY_WRITE
"KX" SDDL_KEY_EXECUTE KEY_EXECUTE

Mandatory label rights

"NR" SDDL_NO_WRITE_UP SYSTEM_MANDATORY_LABEL_NO_WRITE_UP
"NW" SDDL_NO_READ_UP SYSTEM_MANDATORY_LABEL_NO_READ_UP
"NX" SDDL_NO_EXECUTE_UP SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP

 

object_guid

A string representation of a GUID that indicates the value of the ObjectType member of an object-specific ACE structure, such as ACCESS_ALLOWED_OBJECT_ACE. The GUID string uses the format returned by the UuidToString function.

The following table lists some commonly used object GUIDs.

Rights and GUID Permission
CR;ab721a53-1e2f-11d0-9819-00aa0040529b Change password
CR;00299570-246d-11d0-a768-00aa006e0529 Reset password

 

inherit_object_guid

A string representation of a GUID that indicates the value of the InheritedObjectType member of an object-specific ACE structure. The GUID string uses the UuidToString format.

account_sid

SID string that identifies the trustee of the ACE.

下面是一个ACE格式的例子:

(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)
结构中有些为空项,其所描述的信息如下:

Print
AceType:       0x00 (ACCESS_ALLOWED_ACE_TYPE)
AceFlags:      0x00
Access Mask:   0x100e003f
                    READ_CONTROL
                    WRITE_DAC
                    WRITE_OWNER
                    GENERIC_ALL
                    Other access rights(0x0000003f)
Ace Sid      : (S-1-0-0)

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值