2. ACL数据结构:ACE、ACL与SID

聊ACL,绕不开它的三个核心零件:ACE、ACL和SID。我刚开始接触Windows权限时,总把ACE和ACL搞混——后来发现,搞懂它们的关系,权限控制就通了一半。

2.1 安全标识符(SID)——权限世界的身份证

SID,全称Security Identifier。说白了,它就是系统里每个安全主体的唯一编号。你想想看,系统怎么知道“张三”是谁?靠用户名?用户名可以改。靠密码?密码会变。SID才是真正不变的标识。

每个用户、每个组、甚至每台计算机,在创建时都会得到一个唯一的SID。这个值在系统内部是全局唯一的,不会重复。

SID的结构长什么样?

一个典型的SID长这样:

S-1-5-21-3623811015-3361044348-30300820-1013

我来拆开给你看:

部分 含义 示例值
S 固定前缀,表示这是一个SID S
1 修订版本号,目前固定为1 1
5 标识符颁发机构(Authority) 5 = NT Authority
21-...-1013 子颁发机构(Subauthorities) 域标识符 + RID

最后那串数字里的最后一个——1013,叫RID(Relative Identifier)。它是在域或本地范围内唯一标识用户或组的编号。

我的经验: 排查权限问题时,我习惯用 whoami /user 或 wmic useraccount get name,sid 快速查SID。有一次客户说“管理员账号删不掉”,我一查SID,发现根本不是内置管理员,而是个同名假账号。

常见的特殊SID

系统里有一些预定义的SID,我列几个你一定会遇到的:

SID 名称 说明
S-1-0-0 Null SID 空标识,一般用不到
S-1-1-0 Everyone 所有人,包括匿名用户
S-1-5-18 Local System 本地系统账户,权限极高
S-1-5-32-544 Administrators 本地管理员组
S-1-5-32-545 Users 本地用户组
注意: 不要手动修改或伪造SID。我曾经见过有人试图通过修改注册表SID来提权——结果系统直接蓝屏。SID的生成和分配是操作系统内核管理的,你动不了。

2.2 ACL条目(ACE)——权限的最小单元

ACE,Access Control Entry。它是ACL里的每一条规则。你可以把它理解成一张小卡片,上面写着:谁可以做什么。

一个ACE包含三个关键信息:

  • SID:哪个用户或组
  • 权限掩码:允许或拒绝哪些操作(读、写、执行等)
  • 类型:允许型还是拒绝型

ACE的两种类型

类型 含义 优先级
允许型(Access Allowed) 授予指定SID某些权限 低
拒绝型(Access Denied) 明确禁止指定SID某些权限 高

这里有个关键点:拒绝型ACE永远排在允许型ACE前面。系统检查权限时,先看有没有拒绝规则,再看允许规则。一旦匹配到拒绝,直接返回“无权限”,不再继续检查。

核心原则: 拒绝优先于允许。这是ACL权限判断的铁律。

ACE的继承机制

在NTFS文件系统中,ACE可以被子文件夹和子文件继承。继承标志有几种:

  • 容器继承(OI):子文件夹继承此ACE
  • 对象继承(CI):子文件继承此ACE
  • 只继承(IO):此ACE只作用于子对象,不作用于当前对象
  • 不继承(NP):子对象不继承此ACE

举个例子:你给D盘根目录的“销售部”组设置了“读取”权限,并勾选了“应用到子文件夹和文件”。那么D盘下所有文件和文件夹都会继承这个ACE。这就是继承的实际效果。

避坑指南: 我曾经在一个项目里,给共享文件夹设置了“拒绝删除”的ACE,但忘了勾选“只应用于子对象”。结果管理员自己也没法删根目录了——最后只能通过安全模式进去改权限。记住:继承标志要精确控制。

2.3 访问控制列表(ACL)——ACE的集合

ACL,Access Control List。它就是一组ACE的列表。每个安全对象(文件、文件夹、注册表键、打印机等)都关联着一个ACL。

ACL分为两种:

类型 全称 作用
DACL 自由访问控制列表 控制谁可以做什么(读、写、执行等)
SACL 系统访问控制列表 控制哪些操作需要被审计(记录日志)

平时我们说的“改权限”,改的就是DACL。SACL一般用于安全审计场景,比如记录谁删除了重要文件。

ACL的内部结构

一个ACL在内存中的布局大致如下:

ACL Header (8字节)
  - 修订版本
  - 大小
  - ACE数量

ACE #1 (拒绝型)
  - SID: S-1-5-32-544 (Administrators)
  - 权限: 完全控制
  - 标志: 0x00

ACE #2 (允许型)
  - SID: S-1-5-21-...-1013 (张三)
  - 权限: 读取 + 写入
  - 标志: 0x09 (OI|CI|IO)

ACE #3 (允许型)
  - SID: S-1-1-0 (Everyone)
  - 权限: 读取
  - 标志: 0x00

注意顺序:拒绝型ACE在前,允许型ACE在后。这是Windows强制要求的排序规则。

重要: 如果你用API直接操作ACL,必须保证ACE按正确顺序排列。否则系统会拒绝应用这个ACL。我见过不少开发者在调用 SetSecurityInfo 时踩了这个坑——ACE顺序不对,权限设置失败。

2.4 三者的关系——一张图说清楚

下面这张图展示了SID、ACE、ACL和Security Object之间的关系:

ACL数据结构关系图 安全对象 ACL(访问控制列表) DACL(权限控制) SACL(审计控制) ACE列表 ACE #1(拒绝型) ACE #2(允许型) SID 核心关系 1个安全对象 对应1个ACL ACL包含N个ACE 每个ACE绑定1个SID

从这张图可以看得很清楚:一个安全对象关联一个ACL,ACL里包含多个ACE,每个ACE绑定一个SID。这就是ACL权限控制的完整数据链路。

2.5 实战:用PowerShell查看ACL

光说不练假把式。我们直接上手看看真实系统的ACL长什么样:

# 查看文件或文件夹的ACL
Get-Acl -Path "C:\MyFolder" | Format-List

# 只看DACL中的ACE
(Get-Acl -Path "C:\MyFolder").Access | Format-Table IdentityReference, FileSystemRights, AccessControlType, IsInherited -AutoSize

输出示例:

IdentityReference  FileSystemRights  AccessControlType  IsInherited
-----------------  ----------------  -----------------  -----------
BUILTIN\Users      ReadAndExecute    Allow              True
BUILTIN\Admin...   FullControl       Allow              True
张三               Modify            Allow              False

看到没?每一行就是一个ACE。IdentityReference就是SID对应的用户名,FileSystemRights是权限,AccessControlType是允许还是拒绝。

我的习惯: 排查权限问题时,我第一件事就是跑 Get-Acl | Format-List。先看ACL里有没有拒绝型ACE,再看允许型ACE的顺序。很多“明明有权限却访问不了”的问题,都是拒绝型ACE在作怪。

2.6 本章小结

来,我们捋一下:

  • SID 是身份标识,每个用户/组唯一
  • ACE 是权限规则,告诉系统谁可以做什么
  • ACL 是ACE的集合,挂在每个安全对象上
  • 拒绝型ACE优先级高于允许型ACE
  • ACE的继承标志控制权限是否向下传播