什么是强制访问控制MAC
强制访问控制(Mandatory Access Control,简称MAC)是一种由操作系统内核统一实施的安全机制。在MAC体系下,系统中的每个主体(进程、用户)和每个客体(文件、目录、端口、设备)都被打上安全标签或安全上下文,访问是否被允许完全由预定义的安全策略决定。与传统的自主访问控制不同,资源拥有者没有权力修改这些策略,也无法把访问权随意授予他人,因为策略的制定权只属于安全管理员,执行权只属于内核。
举个例子,在DAC模型下,如果你是某个文件的拥有者,你可以执行chmod把文件变成任何用户都可读。但在MAC模型下,即使你是root之外的拥有者,如果安全策略规定你的进程域不允许读取该文件的安全级别,内核会在系统调用层面直接拒绝这次访问,任何用户态手段都绕不过去。这就是强制二字的含义:控制是强制的、不可协商的,对所有进程一视同仁。
MAC的典型实现包括Linux上的SELinux和AppArmor、FreeBSD的MAC框架、macOS的Sandbox与Seatbelt,以及Windows的完整性级别机制(Integrity Level)。它们的具体形态各异,但核心思想一致:把安全决策从用户态收归到内核的统一策略引擎中,让每一次open、exec、connect等敏感操作都经过策略检查。

MAC与DAC的核心区别
DAC(Discretionary Access Control)是大多数人在Linux或Windows上最熟悉的权限体系,也就是owner、group、others对应的rwx权限位。DAC的特点是权限跟着资源走,资源的拥有者可以自主决定把权限分给谁。这种模型灵活易用,但有一个致命弱点:一旦进程被攻破或用户被欺骗运行了恶意代码,恶意代码会继承该用户的全部权限,DAC无法阻止它以合法身份滥用权限。
MAC则从另一个维度构建防线。它引入安全上下文的概念,权限不再只取决于资源的拥有者,还取决于主体与客体的安全标签是否匹配策略规则。以SELinux为例,系统中每个进程运行在特定的域(domain)中,每个文件带有特定的类型(type),策略规则明确规定哪个域可以对哪个类型执行哪些操作。即使一个HTTP服务进程被攻破,由于策略只允许它读写网页目录、绑定特定端口,攻击者也难以横向渗透到系统其他部分。
| 对比维度 | DAC自主访问控制 | MAC强制访问控制 |
|---|---|---|
| 权限决定者 | 资源拥有者 | 系统安全策略与内核 |
| 灵活性 | 高,用户可自由授权 | 较低,策略需统一规划 |
| 抗攻击能力 | 弱,权限可被继承滥用 | 强,可限制被攻破进程的破坏范围 |
| 管理成本 | 低 | 高,需要编写和维护策略 |
| 典型代表 | Unix权限位、Windows ACL | SELinux、AppArmor、macOS沙箱 |
需要注意的是,MAC并不是要取代DAC,而是在DAC之上叠加一层强制约束。一次访问请求通常要先通过DAC的属主与权限位检查,再通过MAC的策略检查,两道关卡都放行才算真正获得访问权。两者配合使用,才能兼顾易用性与安全性。
经典安全模型与MAC的理论基础
强制访问控制的理论根基可以追溯到上世纪七十年代提出的几个经典安全模型。其中最著名的是Bell-LaPadula模型(BLP),它源自军方对机密信息的保护需求,核心是两条规则:不上读、不下写。即低密级主体不能读取高密级客体,高密级主体不能向低密级客体写入信息。这组规则保证了信息不会从高保密级别流向低保密级别,是保密性导向的经典设计。
与之相对的是Biba模型,它关注的是完整性而非保密性,规则正好相反:不上写、下读。低完整性级别的主体不能修改高完整性级别的数据,高完整性级别的进程也不应读取不可信的低完整性数据,以防数据被污染。现代系统中Windows的完整性级别机制(低、中、高、系统四级)可以看作Biba思想的一种工程化简化版本。
另一个在工程中广泛落地的是基于角色的访问控制RBAC。严格来说RBAC介于DAC和MAC之间,它通过角色这一中间层把用户与权限解耦,管理员给角色分配权限、给用户分配角色,从而实现集中化的权限管理。很多MAC实现(如SELinux的多级安全策略与角色组合)都借鉴了RBAC的组织方式。理解这些模型,有助于在实际工作中针对保密性、完整性、职责分离等不同目标选择合适的策略设计。
主流MAC实现与配置实践
SELinux是MAC在Linux上最完整的实现,由美国国家安全局主导开发,现已集成进主流内核。它采用标签式策略,每个进程和文件都有形如user:role:type:level的安全上下文,可以用ls -Z和ps -Z命令查看。下面是一个典型的排查与配置场景:当Web服务因SELinux拒绝而无法读取自定义目录时,需要调整文件的安全上下文而不是简单关闭SELinux。
# 查看文件和进程的安全上下文 ls -Z /var/www/html/index.html ps -Z $(pidof nginx) # 给自定义网站目录打上正确的httpd类型标签 semanage fcontext -a -t httpd_sys_content_t "/srv/mysite(/.*)?" restorecon -Rv /srv/mysite # 允许httpd监听非标准端口 semanage port -a -t http_port_t -p tcp 8080 # 临时切换SELinux模式排查问题(enforcing为强制模式) getenforce setenforce 0
AppArmor则是另一种风格的实现,它基于路径而非标签,策略文件针对单个可执行程序描述其允许访问的文件路径、能力和网络权限。由于配置直观、学习曲线平缓,AppArmor被Ubuntu和SUSE等发行版采用为默认方案。下面是一份简化的AppArmor配置示例,展示如何限制一个应用只能访问指定目录:
#include <tunables/global>
/usr/bin/myapp {
#include <abstractions/base>
# 只允许读写自身数据目录
/var/lib/myapp/** rw,
# 只允许读取配置文件
/etc/myapp.conf r,
# 禁止访问用户主目录敏感文件
deny @{HOME}/.ssh/** rw,
# 允许网络访问
network inet stream,
}macOS则通过沙箱机制(底层是Seatbelt策略引擎)实现强制访问控制,所有来自App Store的应用默认运行在沙箱中,通过entitlements声明所需权限,未经声明的能力一律拒绝。容器技术如Docker底层也大量依赖SELinux或AppArmor提供的强制隔离,加上seccomp系统调用过滤,共同构成容器的安全边界。
MAC的实际应用场景与落地建议
MAC最有价值的应用场景是服务隔离与纵深防御。以一台对外提供Web服务的服务器为例,nginx、PHP-FPM、MySQL、日志收集组件各自运行在受限的域中,策略明确规定:nginx只能读网页文件、绑定80和443端口;PHP-FPM只能写上传目录;MySQL只能访问自己的数据目录。即使其中某个组件因漏洞被攻破,攻击载荷也被牢牢锁死在该域内,无法读取系统敏感文件、无法篡改其他服务的数据、无法建立反向连接外传数据。
第二个典型场景是多级安全环境,例如政府、军工、金融行业中需要处理不同密级数据的系统。借助MLS多级安全策略,可以确保处理绝密数据的进程绝不会把数据写入公开目录,涉密终端上的用户即使操作失误也不会造成密级跨越。第三个场景是移动操作系统,Android和iOS内核都内置了强制访问控制机制,每个应用拥有独立的UID和SELinux上下文,这正是不获取授权就无法读取通讯录和短信的根本原因。
落地MAC时建议遵循循序渐进的原则。第一步,先以宽容模式(SELinux的permissive或AppArmor的complain模式)运行,收集日志分析哪些访问会被拒绝,避免一刀切导致业务中断。第二步,优先保护风险最高的对外服务,从通用策略逐步细化到自定义策略。第三步,把策略文件纳入版本控制,任何修改都经过评审和测试环境验证。同时要建立完善的审计机制,配合audit日志持续监控被拒绝的访问请求,及时发现异常行为。强制访问控制带来的管理成本是真实的,但它换来的安全边界同样真实,对于任何承载重要业务的系统而言,这笔投入都是值得的。