Windows访问控制是一个比较大的题目,因此计划用一系列的文章简单谈一下这个。本篇是开篇,介绍SID。
Windows访问控制定义
Windows访问控制的含义可以参考MSDN的描述:Access control refers to security features that control who can access resources in the operating system. Applications call access control functions to set who can access specific resources or control access to resources provided by the application Access Control (Authorization) 。从上述的描述中,我们可以看出访问控制主要是Windows提供了一个机制用来控制谁可以访问特定的资源,因此本系列所描述的访问控制大部分是对于资源(或者说是安全对象)的访问控制。
考虑资源访问控制这句话,我们需要考察四个点:
- 资源的定义;
- 资源的属主;
- 资源的受访问权限如何定义;
- 用户或者说是进程(线程)如何获取获取对资源的访问权限。
另外我们之所以说本系列所描述的访问控制大部分是对于资源(或者说是安全对象)的访问控制,是因为在实际的编码过程中,执行系统管理任务也是访问控制模型的一部分,也就是特权(priviledge),而这块内容也会在后续的文章中讲到。
熟悉Linux的同学会发现关于资源属主、SID,特权在Linux中也有类似的概念,后续我写Linux访问控制时会再说明对比。
资源定义
资源或者更准确的名称可以叫安全对象(secure object),我个人的理解时创建时可以使用安全描述符(security description)控制访问权限的的对象。例如文件、进程、线程、信号量等内核对象。
但是我个人觉得除了这些内核对象,窗口等用户对象也可以算作资源的一种。基于以下两个原因:
- Windows本身提供了一些安全机制保证这些用户对象的安全性,例如无法跨session访问;
- Windwos提供了一些API(UIPI)来供开发者加强这些对象的安全性,如果控制窗口是否可以接受低完整性进程的窗口消息。
所以在本系列中我也会大致介绍用户对象的一些安全函数及机制。
SID的含义及格式
SID在MSDN中的定义如下:A security identifier is used to uniquely identify a security principal or security group. Security principals can represent any entity that can be authenticated by the operating system, such as a user account, a computer account, or a thread or process that runs in the security context of a user or computer account.What are security identifiers?
可以看出SID在系统中唯一地标识了某个安全实体或者安全组,也就是说我们的用户账户,用户组等都有一个SID关联,并且这个SID至少能保证在当前系统中是唯一的。
Windows中资源的属主概念是通过SID实现的,因为SID可以唯一地标识某个安全实体。
打开CMD,执行 whoami /all
,可以看到当前你正在登录使用的账户的SID及组信息,以下是在我计算机中的输出:
whoami /all
的输出包含三部分:用户名及SID,用户所属的组及当前账户的特权。
根据MSDN的描述,SID的组成格式为 S-R-X-Y1-Y2-Yn-1-Yn
,其中S代表当前串为SID,R代表SID版本(revision level),X代表权限级别,Y1,Y2…Yn子权限级别。以上图中几个SID为例:
S-1-5-21-304837936-1571026108-1873824453-1001
:
- 1代表版本,目前SID所有的版本应该都是1;
- 21代表权限级别,通用的权限级别如下图:
SID中的5即NT Authority; - 21-304837936-1571026108-1873824453-1001即子权限级别:
a. 21-304837936-1571026108-1873824453是domain 标识符,唯一地标识当前系统的domain;
b. 1001是RID(relative ID),表示当前domain中的相对ID,类似相对路径的概念;
c. 21是Win预定义的值,查看 winnt.h 我们可以看到#define SECURITY_NT_NON_UNIQUE (0x00000015L)
,这个值的含义是SID值通过最后添加的RID值而变得唯一。这个很好理解,你尝试在你机器中创建几个账户就会发现,所有账户的SID大部分字段都相同,只有RID在变化,这也就是NON_UNIQUE的含义;
d. 查看winnt.h,可以看到如下定义:#define SECURITY_NT_NON_UNIQUE_SUB_AUTH_COUNT (3L)
,也就是说在21(NON_UNIQUE)的情况下,子权限的数量为3(去除21这个权限级别),也就是SID串中的 304837936-1571026108-1873824453,这三个数值为随机数,在系统首次被安装后生成;
e. 用户自己创建的账户据说RID是从1000开始,但是我测试的所有机器都是1001开始,有点疑惑。
接下来我们看看当前账户所属某个组的SID的分析:
BUILTIN\Administrators 别名 S-1-5-32-544 只用于拒绝的组
组名是 BUILTIN\Administrators ,标识其为内建的管理员组;
S-1-5的含义不变,32的定义为 SECURITY_BUILTIN_DOMAIN_RID,也就是内建组;544定义为
DOMAIN_ALIAS_RID_ADMINS,就也是管理员组。所以当前SID代表内建的SID。
当时当前组的最后一部分为只用于拒绝的组
,这是因为我在执行whoami时没有打开UAC,所以当前用户是不具备管理员权限的,当打开UAC再执行命令就会看到启用的组
。这个设计是基于安全的考虑,即某个用户是管理员组内的,但是却不具备管理员权限。
以上对whoami
输出的简单分析,我们可以察觉,某个用户所具备的权限是基于其属于哪些组及特权决定的,单一的账户SID只是一个标识符,不具备任何魔力。
其他
我们可以打开任务管理器,查看当前系统中运行的进程及对应的账户,以下是我机器中部分进程及账户:
除了我的用户账户(81337)以后,还有Local Service,Network Service, System三个账户也在运行。这三个账户属于内建账户,查看MSDN我们可以看到:
同样我们打开注册表,定位到 HKEY_USER目录,可以看到
也就是说所有正在运行的账户都加载了对应账户注册表。这些账户注册表所在的位置可以查看:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist,以下是我机器中的部分数据:
另外之所以要创建这么多内建SID的原因也是基于安全的考虑,可以最小化地定制其权限,也就是定制其所属的组及特权,防止权限的滥用。