3、ACL类型详解:自主访问控制列表(DACL)与系统访问控制列表(SACL)
聊到Windows权限体系,很多人一上来就被DACL和SACL这两个缩写搞晕了。我当年刚接触时也一样,总觉得它们差不多。其实说白了,DACL管的是“谁能进”,SACL管的是“谁来过”。一个控制访问,一个记录审计,分工非常明确。
这一章,我们就彻底把它们掰开揉碎讲清楚。
3.1 自主访问控制列表(DACL)
DACL是Windows安全模型里最核心的部分。你平时配文件夹权限、注册表权限、打印机权限,改的都是DACL。
DACL的本质是什么?
它是一个有序的访问控制条目(ACE)列表。每个ACE指定了一个用户或组,以及允许或拒绝的权限。系统在判断一个进程能否访问某个对象时,会按顺序遍历DACL中的ACE,直到找到匹配的规则。
关键点:DACL中未明确允许的访问,默认就是拒绝。这就是“隐式拒绝”原则。很多安全漏洞就是因为开发者以为“没写拒绝就是允许”,结果被钻了空子。
3.1.1 DACL的ACE类型
DACL里只有两种ACE:允许(Access-Allowed)和拒绝(Access-Denied)。但它们的排列顺序有讲究。
| ACE类型 | 含义 | 典型场景 |
|---|---|---|
| Access-Denied ACE | 显式拒绝指定权限 | 禁止某个用户写入,即使他属于允许写入的组 |
| Access-Allowed ACE | 显式授予指定权限 | 给某个用户或组赋予读取、写入等权限 |
我曾经踩过一个坑:在给一个共享文件夹配权限时,我把拒绝ACE放在了允许ACE后面。结果发现某个用户明明被拒绝了写入,却依然能写入文件。查了半天才想起来——Windows是按顺序处理ACE的,拒绝ACE必须排在允许ACE前面才有效。这个顺序问题,坑过不少人。
3.1.2 DACL的权限掩码
每个ACE里都带一个权限掩码,用32位二进制位表示。常用的权限位包括:
- 通用权限:GenericRead、GenericWrite、GenericExecute、GenericAll
- 标准权限:Delete、ReadControl、WriteDAC、WriteOwner、Synchronize
- 特定权限:取决于对象类型,比如文件的ReadData、WriteData,注册表的QueryValue、SetValue
我个人的习惯是,能用特定权限就别用通用权限。通用权限映射到特定权限时,有时会多出你意想不到的权限位,造成权限过大。
3.1.3 DACL的继承机制
DACL支持从父对象继承。比如你给一个文件夹设了权限,默认子文件和子文件夹都会继承。继承的ACE和直接设置的ACE在DACL里是分开存储的,系统会用“继承标志位”来区分。
小技巧:排查权限问题时,先用工具查看“有效权限”,它会帮你算出继承和显式ACE叠加后的最终结果。Windows自带的“高级安全设置”里就有这个功能。
3.2 系统访问控制列表(SACL)
SACL不控制访问,它只记录访问。说白了,SACL就是审计规则列表。你告诉系统:“帮我盯着谁对这个文件做了什么操作”,系统就会把匹配的操作记到安全日志里。
SACL的ACE类型
SACL里只有两种ACE:审计成功(System Audit Success)和审计失败(System Audit Failure)。
| ACE类型 | 含义 | 审计日志事件ID |
|---|---|---|
| System Audit Success | 记录成功的访问尝试 | 4663(成功) |
| System Audit Failure | 记录失败的访问尝试 | 4663(失败) |
3.2.1 SACL的典型应用场景
- 合规审计:比如金融系统要求记录所有对客户数据的访问
- 入侵检测:记录对敏感文件的失败访问,可能是攻击者在试探
- 权限验证:上线新系统时,先审计一段时间,看看实际访问模式是否符合预期
我建议:生产环境不要一股脑把所有对象的SACL都打开。审计日志量会爆炸,日志服务器很快就会被撑爆。先圈定最敏感的对象,比如域控上的NTDS.dit、财务共享文件夹、HR数据库文件,针对这些对象配SACL就够了。
3.3 DACL vs SACL:一张图看懂
为了让你更直观地理解两者的关系,我画了张图:
3.4 实战:用PowerShell查看DACL和SACL
光说不练假把式。我们直接上手看看真实系统里的DACL和SACL长什么样。
# 查看文件的DACL
$path = "C:\Important\report.xlsx"
$acl = Get-Acl -Path $path
# 输出DACL
Write-Host "=== DACL ===" -ForegroundColor Green
$acl.Access | Where-Object { $_.IsInherited -eq $false } | Format-Table IdentityReference,
AccessControlType, FileSystemRights, IsInherited -AutoSize
# 输出SACL
Write-Host "=== SACL ===" -ForegroundColor Yellow
$acl.Audit | Format-Table IdentityReference, AuditFlags, FileSystemRights -AutoSize
注意:查看SACL需要管理员权限。如果你用普通用户跑上面的脚本,SACL部分会返回空。这是Windows的安全设计——审计配置本身是敏感信息,不能随便让人看。
3.5 避坑指南:DACL和SACL的常见误区
- 误区一:DACL为空就是允许所有人访问
恰恰相反。DACL为空意味着没有显式允许任何访问,所有访问都会被拒绝。只有DACL不存在(null DACL)时,才表示允许所有访问。但null DACL极少见,微软也不推荐用。
- 误区二:SACL配了就能自动记录日志
配了SACL只是第一步。你还需要在“本地安全策略”或“组策略”中开启对应的审计策略(比如“审核对象访问”)。策略没开,SACL配得再精细也不会产生日志。
- 误区三:ACE顺序无所谓
我前面已经提过了,顺序很重要。拒绝ACE必须排在允许ACE前面。Windows处理ACE时,一旦匹配到拒绝ACE就直接拒绝,不再继续往下看。这是性能优化,也是安全设计。
我曾经见过一个生产事故:某运维给域控上的一个关键GPO配了SACL,想审计谁在修改它。结果审计策略没开,日志里啥也没有。等出了安全问题想溯源时,才发现审计根本没生效。白白浪费了排查时间。所以我的习惯是:配完SACL后,立刻手动触发一次访问,然后去事件查看器里确认4663事件有没有出现。
3.6 小结
DACL和SACL是Windows安全体系的两大支柱。DACL管权限,SACL管审计。理解它们的区别和配合方式,是做好权限控制的基础。
记住几个关键点:DACL的隐式拒绝、ACE的顺序、SACL需要配合审计策略。把这些搞清楚了,Windows权限这块你就掌握了七成。