访问控制模型(Access Control Model)是指Windows操作系统关于安全性的一个概念,由访问令牌和安全描述符两部分构成,其中访问令牌是指由当前登录的Windows账号的用户持有,其中会包含了该账号的基础信息,包括用户帐户的标识和特权信息,安全描述符由要访问的对象持有,里面会包含当前对象的安全信息。假设当用户登录时,操作系统会对用户的帐户名和密码进行身份验证, 当登录成功时,系统会自动分配访问令牌(Access Token),访问令牌包含安全标识符,用于标识用户的帐户以及该用户所属的任何组帐户,当我们去创建一个进程也就是访问一个资源(进程资源)的时候,Access Token会被复制一份给进程,进程通过它的创建者所给它设置的安全描述符中的ACL来判断我们是否可以去访问,是否有权限去执行某步操作。
Windows的访问令牌(Access Token)分为两种类型:主令牌(Primary Token)和模拟令牌(Impersonation Token),它代表某种请求或登录机制的凭证,使用户在短时间内执行某种身份认证或权限操作的验证性信息。Windows系统中每个用户登录账号都生成对应的一个访问令牌,在当用户使用账号登录到操作系统时,系统会将所登录的账号与安全数据库(SAM)中存储的数据进行对比验证,验证成功后才会生成一个访问令牌,当我们打开某个进程或者线程正在与具有安全描述符的对象进行交互的时候,系统将会携带令牌进行访问,以此来表示用户身份,如图1-1所示。
当创建一个进程的时候,Windows操作系统的内核都会给进程去创建分配一个主令牌,每一个进程都含有一个主令牌,它描述了进程相关用户账号的安全上下文,同时一个线程可以模拟一个客户端账号,允许此线程与安全对象交互时用客户端的安全上下文。一个正模拟客户端的线程拥有一个主令牌和一个模拟令牌。(主令牌是与进程相关的,模拟的令牌是与模拟令牌的线程相关的)。
主令牌也叫授权令牌(Delegation Token),是一种认证机制,用于交互式登录,为了减少不必要的认证工作而出现的,由 Windows操作系统的内核创建并分配给进程的默认访问令牌,每一个进程都会有一个主令牌,其中描述了登录进程返回的SID,与当前进程相关的用户帐户的安全组的特权列表,代表系统可以使用令牌使用户可以访问那些安全对象,及控制用户可以执行那些相关系统操作,通常用于本地登录及远程RDP登录的场景。
一个完整的主令牌包含了如下内容:
对于模拟令牌,在默认情况下,当线程开启的时候,所在进程的主令牌会自动附加到当前的线程上来作为线程的安全上下文。而线程可以运行在另一个非主令牌的访问令牌下执行,这个令牌被称为模拟令牌,通常会用于客户端/服务器之间的通信。假设在文件共享的时候,服务器需要用户令牌来验证用户的权限,而服务器无法直接获取用户的访问令牌,因为该令牌是锁死在内存中无法访问的,所以它就会需要生成一个模拟令牌。
在Windows操作系统中,通常使用安全标识符(SecurityIdentifier,SID)来标识在系统中执行操作的实体,安全标识是一个唯一的字符串,其可以代表用户、用户组、域、域组、域成员等角色身份。
SID是一种可变长度的数值,SID值通常由SID结构信息和唯一标识受托者组成,SID包含如下的组成部分,如图1-2所示。
在整个Windows系统中,SID使用标识符机构值和子权限值的组合,即使不同的SID颁发机构颁发出相同的RID的值,其SID也不会相同的,因此在任何计算机和域中,Windows都不会颁发出两个相同的SID。接下来我们以实际的SID为例。
每一个SID都包含了一个S的前缀,不同的部分使用连字符“-”进行分割,以下述SID为例,详解为大家介绍SID在Windows操作系统中的组成部分,如图1-3所示。
S-1-5-21-1315137663-3706837544-1429009142-502
通过上述对SID的结构分析来看,我们知道SID结构是一组标识通用用户或通用组的SID,它们的值在所有操作系统中保持不变。在Windows操作系统中其实也内置了一些本地SID和域SID,例如Domain User组,用于代表域中所有的用户账户,其SID为S-1-5-21-domain-513;还有Everyone组,代表所有的用户账户,该组的SID为S-1-1-0。表1-1列举出了当前Windows操作系统中比较基本常见的SID以及它们的所属名称和具体作用。
表1-1 常见的SID以及他们的所属名称和具体作用
SID | 名称 | 作用 |
---|---|---|
S-1-5-21-domain-512 | Domain Admins | 一个全局组,其成员被授权管理该域。默认情况下,DOMAIN_ADMINS组属于所有加入域的计算机(包括域控制器)上的 Administrators 组。Domain Admins 是该组的任何成员创建的任何对象的默认所有者。 |
S-1-5-domain-513 | Domain Users | 包含域中所有用户帐户的全局组 |
S-1-5-domain-500 | Administrator | 系统管理员的用户帐户默认情况下,它是唯一可以完全控制系统的用户帐户 |
S-1-5-root domain-519 | Enterprise Admins | 纯模式域中的通用组,或混合模式域中的全局组该组被授权在 Active Directory中进行森林范围的更改,例如添加子域 |
S-1-5-domain-515 | Domain Admins | 一个全局组,包括已加入域的所有客户端和服务器 |
S-1-5-7 | Anonymous | 代表匿名登录的组 |
S-1-5-18 | Local SYSTEM | 操作系统使用的帐户 |
S-1-1-0 | Everyone | 包含所有用户的组 |
S-1-5-33 | WRITE_RESTRICTED_CODE | 允许对象具有ACL的SID,该ACL允许具有写入限制令牌的任何服务进程写入对象 |
在Windows操作系统中,因常见的SID名称可能会有所不同,我们应该通过使用API函数来从预定义的标识符授权和相对标识符定义的常量中构建SID,例如:通过SECURITY_WORLD_SID_AUTHORITY和SECURITY_WORLD_RID两个常量来显示代表所有用户的特殊组的通用SID——S-1-1-0,其中S表示为SID,1表示为SID的修订级别,剩下的1和0这两位数字分别是SECURITY_WORLD_SID_AUTHORITY与SECURITY_WORLD_RID的值数。如果我们要确认登录用户是否是特定已知组的成员,就需要使用AllocateAndInitializeSid函数为已知组构建SID,用于标识本地计算机的管理员组的众多所知SID,然后使用EqualSID函数将SID与用户所在组的组SID进行比较,同时当我们要释放由AllocateAndInitializeSid分配的SID时,只需要调用FreeSid函数来进行释放即可,而不能直接使用其SID名称(考虑到不同版本的操作系统上有不同的名称)。如果我们需要使用SID,可以调用其已有的Windows API来满足需求,表1-2是可供我们调用的API函数列表。
表1-2 可供调用的API函数列表
API函数 | 作用描述 |
---|---|
AllocateAndInitializeSid | 使用指定数量的子权限分配和初始化SID |
ConvertSidToStringSid | 将SID转换为适合于显示、存储或传输的字符串格式。 |
ConvertStringSidToSid | 将字符串格式的SID转换为有效的功能性SID |
CopySID | 将源SID复制到缓冲区 |
EqualPrefixSid | 测试两个SID前缀值是否相等。 SID前缀是除最后一个子权限值以外的整个SID |
EqualSid | 测试两个SID是否相等。它们必须完全匹配才能被视为相等 |
FreeSID | 通过使用AllocateAndInitializeSid函数释放先前分配的SID。 |
GetLengthSid | 检索SID的长度 |
GetSidldentifierAuthority | 检索指向SID标识符权限的指针 |
GetSidLengthRequired | 检索存储具有指定数量的子权限的SID所需的缓冲区大小 |
GetSidSubAuthority | 检索指向SID中指定的子机构的指针 |
GetSidSubAuthorityCount | 检索SID中的子机构数. |
InitializeSid | 初始化SID结构 |
IsValidSid | 通过验证修订号在已知范围内并且子授权机构的数量小于最大数量,来测试SID的有效性 |
LookupAccountName | 检索与指定帐户名对应的SID |
LookupAccountSid | 检索与指定的SID对应的帐户名 |
接下来将介绍可用于构建常见的SID表以及标识符权限和子权限的常量表。表1-3列出了预定义的标识符颁发机构。
表1- 3 预定义的标识符颁发机构
标识符颁发机构 | 标识符机构值 | SID 字符串前缀 | 作用 |
---|---|---|---|
SECURITY_NULL_SID_AUTHORITY | 0 | S-1-0 | 用于颁发机构不可知时 |
SECURITY_WORLD_SID_AUTHORITY | 1 | S-1-1 | 用于创建代表所有用户的安全标识符 |
SECURITY_LOCAL_SID_AUTHORITY | 2 | S-1-2 | 用于创建代表本地终端的登录用户的安全标识符 |
SECURITY_CREATOR_SID_AUTHORITY | 3 | S-1-3 | 用于创建代表某个对象的创建者或所有者的安全标识符 |
SECURITY_NT_AUTHORITY | 5 | S-1-5 | 代表操作系统本身的一部分,以S-1-5开头的安全标识符都是由计算机或域发布的 |
SECURITY_AUTHENTICATION_AUTHORITY | 18 | S-1-18 | 用于指定声明客户端身份的身份验证机构 |
如表1-4所示,以下RID值与通用已知SID一起使用。标识符颁发机构列显示标识符颁发机构前缀,可以使用该前缀组合RID来创建通用已知SID。
表1-4 RID相对标识符颁发机构
相对标识符颁发机构 | 相对标识符值 | 标识符颁发机构 |
---|---|---|
SECURITY_NULL_RID | 0 | S-1-0 |
SECURITY_WORLD_RID | 0 | S-1-1 |
SECURITY_LOCAL_RID | 0 | S-1-2 |
SECURITY_CREATOR_OWNER_RID | 0 | S-1-3 |
SECURITY_CREATOR_GROUP_RID | 1 | S-1-3 |
以下为RID所对应的每一个域,如表1-5所示。
表1-5 RID所对应的每一个域
RID | 相对标识符 | 描述 |
---|---|---|
DOMAIN_USER_RID_ADMIN | 500 | 域中的管理用户帐户。 |
DOMAIN_USER_RID_GUEST | 501 | 域中的来宾用户帐户。 没有帐户的用户可以自动登录此帐户。 |
DOMAIN_GROUP_RID_USERS | 513 | 包含域中所有用户帐户的组。 所有用户都将自动添加到此组。 |
DOMAIN_GROUP_RID_GUESTS | 514 | 域中的组来宾帐户。 |
DOMAIN_GROUP_RID_COMPUTERS | 515 | "域计算机"组。 域中的所有计算机都是此组的成员。 |
DOMAIN_GROUP_RID_CONTROLLERS | 516 | 域控制器组。 域中的所有域控制器都是此组的成员。 |
DOMAIN_GROUP_RID_CERT_ADMINS | 517 | 证书发布者的组。 运行 Active Directory 证书服务的计算机是该组的成员。 |
DOMAIN_GROUP_RID_SCHEMA_ADMINS | 518 | 架构管理员的组。 此组的成员可以修改 Active Directory 架构。 |
DOMAIN_GROUP_RID_ENTERPRISE_ADMINS | 519 | 企业管理员的组。 此组的成员具有对 Active Directory 林中所有域的完全访问权限。 Enterprise管理员负责林级别的操作,如添加新域或删除新域。 |
DOMAIN_GROUP_RID_POLICY_ADMINS | 520 | 策略管理员的组。 |
安全描述符(Security Descriptor)包含了访问控制列表(DACL)以及(SACL)系统访问控制列表,而其中SACL是用来记载对象访问请求的日志,DACL中包含了ACE(访问控制项)。该项设置了允许用户的访问权限,安全描述符绑定在每个被访问对象上,假设当我们携带访问令牌去访问一个带有安全描述符的对象,安全描述符会检测我们令牌是否具有可访问的权限。
安全描述符包含了安全描述组织架构及其关联的安全信息,如下是安全描述符的组织结构及安全描述符包含的安全信息详细介绍。
安全描述符由SECURITY_DESCRIPTOR结构及其关联的安全信息组成。结构体如下所示:
typedef struct _SECURITY_DESCRIPTOR {
BYTE Revision;
BYTE Sbz1;
SECURITY_DESCRIPTOR_CONTROL Control;
PSID Owner;
PSID Group;
PACL Sacl;
PACL Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
安全描述符包含如下安全信息:
当我们需要查看某个对象具有什么安全描述符时,可以右击该对象,选择“属性”,进一步查看“安全”,如图1-4所示,可看到当前对象所具有的安全描述符。
DACL即任意访问控制列表,其中包含访问控制项(ACE),决定当前用户以哪种权限,去访问对象,系统使用以下方式为新对象构建DACL。
1)对象当前的DACL是来自对象创建者指定的安全描述符的DACL。除非在安全描述符的控制位中设置了SE_DACL_PROTECTED位,否则系统会将所有可继承的ACE合并到指定的DACL中。
2)如果创建者未指定安全描述符,则系统将从可继承的ACE构建对象的DACL。
3)如果未指定安全描述符,并且没有可继承的ACE,则对象的DACL是来自创建者的主令牌或模拟令牌的默认DACL。
4)如果没有指定的、继承的或默认的DACL,则系统将创建不具有DACL的对象,从而允许所有人完全访问该对象。
系统访问控制列表(SACL),主要使用于系统审计,同时可以指定哪些些用户的行为操作记录会被保存到系统日志中。系统使用以下方式为新对象构建SACL。
1)对象的SACL是对象创建者指定的安全描述符中的SACL。除非在安全描述符的控制位中设置了SE_SACL_PROTECTED位,否则系统会将所有可继承的ACE合并到指定的SACL中。即使SE_SACL_PROTECTED位置已经设置,来自父对象的SYSTEM_RESOURCE_ATTRIBUTE_ACE和SYSTEM_SCOPED_POLICY_ID_ACE也将合并到新对象。
2)如果创建者未指定安全描述符,则系统将从可继承的ACE构建对象的SACL。
3)如果没有指定的或继承的SACL,则该对象没有SACL。
4)要为新对象指定SACL,对象的创建者必须启用SE_SECURITY_NAME特权。如果为新对象指定的SACL仅包含SYSTEM_RESOURCE_ATTRIBUTE_ACE,则不需要SE_SECURITY_NAME特权。如果对象的SACL是从继承的ACE构建的,则创建者不需要此特权。应用程序不能直接操纵安全描述符的内容。Windows API提供了用于在对象的安全描述符中设置和检索安全信息的功能。此外,还有用于创建和初始化新对象的安全描述符的函数。
安全描述符字符串,它是指在安全描述符中存储或传输信息的文本格式。安全描述符包含二进制格式的安全信息,Windows API提供了用于将二进制安全描述符与文本字符串相互转换的功能。字符串格式的安全描述符不起作用,但是对于存储或传输安全描述符信息很有用。假设若要将安全描述符转换为字符串格式,需要调用 ConvertSecurityDescriptorToStringSecurityDescriptor函数。要将字符串格式的安全描述符转换回有效的功能安全描述符,需要调用ConvertStringSecurityDescriptorToSecurityDescriptor函数。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。