第二讲:自主访问控制(DAC)原理与典型案例归纳总结
各位同事,今天咱们聊聊自主访问控制(DAC)。这个概念听起来很基础,但我这些年见过不少事故,根源就是对DAC理解不到位。
说白了,DAC就是「谁拥有资源,谁说了算」。文件的创建者(Owner)可以自己决定谁可以读、谁可以写、谁可以执行。系统只做一件事:帮你检查一下,当前请求的身份是不是在Owner给的允许名单里。
2.1 DAC的核心思想与信任模型
DAC的核心假设是「Owner是理性的」。为什么这么讲?因为你把文件权限交给用户自主管理,默认相信他不会犯傻——比如把公司核心数据库权限开给所有人。
但这个假设在实际中经常翻车。我处理过一次内部数据泄露事件,起因就是一位工程师为了方便调试,把敏感日志目录设成了777。你说他恶意吗?不是。就是图省事。这就是DAC的硬伤:权限下放容易,收回来难;图一时方便,埋长期隐患。
DAC的信任链很简单:
- 用户认证通过后,系统信任该用户
- 用户可将其客体的权限传递给其他用户(通过修改ACL或设置权限位)
- 系统不干预「用户是否应该这么做」——只执行
所以你看,DAC的本质是一个信任代理模型:系统把决策权委托给用户,自己只做门卫。
核心特征总结
- Owner拥有完全控制权:可以更改权限、转让Owner
- 权限可传递:DAC允许Owner授权给其他用户,被授权者(如果拥有授权权限)可继续传播
- 粒度可粗可细:从Unix的三元组(rwx)到文件系统的ACL条目
2.2 经典实现:从Unix权限位到ACL
咱们来拆解两个最常见的DAC实现。大多数工程师至少用过其中一个。
2.2.1 Unix/Linux传统权限模型
每个文件有三组权限:Owner、Group、Others。每组三个位:读(r=4)、写(w=2)、执行(x=1)。组合就是经典的755、644这样的数字。
举个例子:
$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1234 Jan 1 00:00 /etc/shadow
这个文件的Owner是root,Group是shadow。Owner有读写(6),同组用户只有读(4),其他人啥都没有(0)。
但这种模型有个问题:当需要给特定用户(不在Owner的Group里)单独授权时,怎么办?你只能要么改Group,要么改成777——都是糟方案。
我的经验:在Linux服务器上,我见过大量因为Group设置不合理导致的权限泄漏。一个典型场景:运维把普通用户加到了docker组,结果这个用户通过docker挂载宿主机目录绕过了文件权限检查。你看,DAC在这个场景下完全失效——因为docker的访问不经过文件系统的DAC检查。
2.2.2 POSIX ACL与扩展属性
为了弥补三元组粒度过粗的问题,POSIX ACL应运而生。通过 setfacl 和 getfacl 命令,你可以给任意用户或组设置具体权限。
# 给用户alice添加读写权限
$ setfacl -m u:alice:rw- important.doc
# 查看当前ACL
$ getfacl important.doc
# file: important.doc
# owner: bob
# group: staff
user::rw-
user:alice:rw-
group::r--
mask::rw-
other::---
注意那个mask字段。它像一个上限帽:mask会限制所有命名用户和命名组能获得的最大权限。为什么要有mask?我遇到过项目里有人用ACL给了用户rwx,但mask是r-x,结果那个用户执行不了——排查了半天才发现是mask捣乱。
| 实现方式 | 粒度 | 管理复杂度 | 典型应用场景 |
|---|---|---|---|
| Unix三元组(rwx) | 粗(Owner/Group/Other) | 低 | 个人文件、简单共享 |
| POSIX ACL | 细(可对单个用户和组设权限) | 中 | 多用户协作目录、Web服务器 |
| NFSv4 ACL | 最细(继承、审计、告警) | 高 | 企业NAS、文档管理 |
2.3 DAC的典型问题与避坑
我开始做安全审计时,整理过一个DAC常见漏洞清单。这里挑三个最典型的跟你们说说。
2.3.1 权限传播失控(授权膨胀)
DAC允许用户授权给他人,被授权者如果拥有「授权权」(比如ACL中的write_acl权限),就可以继续授权给别人。这就可能形成一条授权链,最终连Owner都搞不清楚谁有权限了。
我遇到过一个真实案例:某公司内部Wiki系统使用DAC管理页面权限。一个项目组的成员A给了B编辑权限,B又给了C,C是外部实习生……结果核心设计文档被实习生误删了。排查时发现Owner(项目组长)根本不知道C的存在。
避坑提示:在实施DAC时,建议对「授权传播」做限制。比如ACL中可以设置 write_acl 权限只给管理员,不给普通用户。或者设置短期授权自动回收机制。
2.3.2 权限提升与文件描述符泄漏
DAC还有一个经典漏洞:特权进程打开一个高权限文件后,如果忘记关闭文件描述符(fd),并且后来fork了子进程,子进程可能继承这个fd,从而绕过DAC检查。
| 场景 | 风险等级 | 典型后果 |
|---|---|---|
| root进程打开/etc/shadow后fork子进程 | 高危 | 子进程可读取密码哈希 |
| Web服务器打开配置文件后生成worker进程 | 中危 | worker可越权读取数据库密码 |
| 容器内进程以root运行,挂载宿主机/passwd | 严重 | 容器内可修改宿主机用户密码 |
我曾经帮一个客户做容器安全加固,发现他们的CI/CD管道容器以root运行,并且把宿主机的/etc/passwd和/etc/shadow映射进去了。容器里DAC不管用——因为容器内看到的文件系统虽然是宿主机的inode,但容器内root对宿主机root没有特权。可问题是,容器内root可以在只读挂载下读取任何文件。这并不是DAC的失败,而是DAC的边界被打破了——容器内的root在宿主机上并不是root,但因为DAC检查只认uid,宿主机文件系统把容器内root当作宿主机root处理了。
解决方案:使用用户命名空间(User Namespace)把容器内root映射成宿主机非特权用户。这样DAC检查能正常执行,容器内root无法越权访问宿主机文件。
2.3.3 临时提权与SUID/SGID滥用
Unix里有SUID和SGID位,允许普通用户以文件所有者的身份执行程序。这本质上也是DAC的一种扩展:Owner通过设置SUID,把自己的权限「借」给执行者。
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 123456 Jan 1 00:00 /usr/bin/passwd
这个s位就是SUID。普通用户执行passwd时,进程的有效UID变成root,可以修改/etc/shadow。这太危险了——任何一个SUID root的程序有漏洞,整个系统就完蛋。
我审计过不少定制化SUID程序,最常见的问题是程序启动后没有及时drop privileges。比如先以root身份打开了一个文件描述符,然后才setuid到普通用户——这时候fd已经被偷出来了。
规则:尽量不要自己写SUID程序。如果必须用,遵守两条:
- 在最早的时间点执行
setuid(getuid())和setgid(getgid()) - 在执行任何用户输入处理前,关闭所有不需要的特权fd
2.4 DAC的适用边界与替代方案
DAC不是银弹。什么场景适合DAC?
- 个人工作环境:自己的电脑,自己决定文件共享给谁
- 小型团队协作:互相信任的几个人共享项目目录
- 操作系统基础权限:作为底层机制,与MAC(强制访问控制)组合使用
什么场景不适合?
- 多租户云平台:不同用户之间不能互相授权
- 高安全性系统:比如金融核心、医疗数据——需要集中管控
- 临时/外部人员访问:应使用RBAC或ABAC,减少人为错误
我们接下来用一张图把DAC的知识体系串起来。
这张图把DAC的决策流程拆成了六步:主体发起请求、访问请求指定操作、客体提供Owner和ACL信息、访问矩阵存储权限元组、引用监控器比对矩阵作出允许/拒绝决策、审计日志记录每次决策。整个链条中,矩阵里的权限条目完全由客体Owner自主设定——这也是「自主」二字的真正含义。
2.5 案例复盘:一个实际DAC权限事故分析
最后分享一个我多年前参与过的真实事件,正好能串联本讲的所有知识点。
背景:某互联网公司内部Git仓库,使用Gitolite作为权限管理(基于DAC+SSH密钥)。每个仓库的Owner可以添加协作者。
事故过程:
- 项目A的Owner给了实习生小明读权限(为了让他学习代码)
- 小明基于项目A的代码,复制了一个私有仓库做实验——按DAC规则,他完全有权利复制
- 小明的私有仓库不小心设成了public(权限位777),被他自己的同学抓到:下载了全部源码
- 源码中包含数据库连接字符串(硬编码)
根因分析:
- DAC权限传播:Owner授权后,小明成了新数据的Owner,他可以自己决定进一步授权
- 缺乏安全培训:Owner没有意识到「读权限」在DAC中可以通过复制泄露数据
- 缺乏审计:没有监控「仓库创建」和「仓库设为public」的动作
改进措施:
- 引入强制访问控制(MAC)层:核心仓库数据打标签,禁止降级到public
- Git仓库控制台增加创建公开仓库的审批流程
- 密钥与代码分离:使用密钥管理服务,严禁硬编码
这个案例告诉我们:DAC的「自主」是把双刃剑。方便用户的同时,也把安全责任推给了非专业人员。我们作为安全工程师,不能简单地说「用户自己授权的,怪谁」——而是要设计好边界,把DAC的权限范围圈在可控的安全域内。
好了,关于DAC的原理和实践就到这儿。记住几个关键点:Owner决定一切,矩阵决定权限,引用监控器只做检查不出声。下一层我们会讲强制访问控制(MAC),到时候你会看到另一种完全不同的哲学。