从 ACL 到零信任:权限系统设计模式的演进之路
从最朴素的"谁对什么有权限",到最复杂的"从不信任,始终验证",权限系统的演进不仅仅是技术的升级,更是安全思维的五次跃迁。
一、全景路线图
arduino
ACL → RBAC → ABAC → ReBAC → Zero Trust
"谁对什么 "谁能做什么" "在什么条件下 "因为你和它 "永远不信任
有什么权限" (角色) 谁能做什么" 有关系所以 每次都验证"
(枚举) (策略) 能做什么"
(关系)
~~~~ ~~~~ ~~~~ ~~~~ ~~~~
朴素信任 组织信任 条件信任 关系信任 零信任
二、四大核心权限模型
1. ACL(Access Control List)访问控制列表
核心思想 :以资源为中心。每个资源绑定一个列表,明确记录"谁"对"它"有"什么权限"。
css
文件A → 张三[读]、李四[读写]
文件B → 张三[读写]、王五[读]
文件C → 李四[读]、王五[读写]
- 优点:概念直观,实现简单,非常适合细粒度的资源级别控制
- 缺点:用户和资源规模扩大后,维护成本呈指数级上升("权限地狱")
- 典型场景:操作系统文件权限(Linux/Windows)、简单的文档管理系统
2. RBAC(Role-Based Access Control)基于角色的访问控制
核心思想 :以角色为桥梁。权限赋予角色,用户通过角色获得权限。
用户 → 角色 → 权限 → 资源/操作
- 优点:高度契合企业组织架构,管理成本大幅降低。新员工入职只需分配角色,离职只需回收角色
- 缺点:复杂场景下会出现"角色爆炸",缺乏上下文感知能力
- 典型场景:绝大多数企业级 SaaS 应用、ERP/CRM 系统、后台管理系统
3. ABAC(Attribute-Based Access Control)基于属性的访问控制
核心思想 :以策略为中心。通过评估四个维度的属性动态计算是否放行:
| 维度 | 举例 |
|---|---|
| 主体属性 | 用户部门、职级、标签 |
| 资源属性 | 文件密级、类型、所有者 |
| 环境属性 | 时间、IP、设备、地理位置 |
| 操作属性 | 读、写、删除、导出 |
sql
示例策略:
IF User.部门 == '财务部'
AND Resource.密级 == '机密'
AND Environment.时间 BETWEEN '工作日9:00-18:00'
AND Environment.IP IN 内网段
THEN Allow
- 优点:极度灵活、细粒度,支持上下文感知,策略与代码解耦
- 缺点:前期设计和规则梳理复杂度高,策略引擎有一定性能开销
- 典型场景:AWS IAM、零信任架构、金融/医疗系统
4. ReBAC(Relationship-Based Access Control)基于关系的访问控制
核心思想 :基于实体之间的图关系来决定权限,源自 Google Zanzibar 论文。
markdown
我能编辑这个文档
← 我是这个文件夹的编辑者
← 这个文件夹属于我的团队
← 团队负责人共享给了我
权限 = 在关系图中是否存在一条允许的路径
- 优点:天然支持复杂的层级继承和协同场景,权限可沿关系链传递
- 缺点:需要图数据库或专用引擎,建模复杂度较高
- 典型场景:飞书/Notion 文档协作、社交媒体、网盘共享
- 代表技术:OpenFGA、SpiceDB
横向对比
| 维度 | ACL | RBAC | ABAC | ReBAC |
|---|---|---|---|---|
| 控制核心 | 资源 | 角色 | 属性/策略 | 图关系 |
| 粒度 | 资源级 | 功能/菜单级 | 数据行/列级 | 资源级 |
| 灵活性 | 低(静态绑定) | 中(静态分配) | 极高(动态计算) | 高(图遍历) |
| 管理复杂度 | 规模大时极高 | 中等 | 初期高,后期好 | 依赖图模型 |
| 适用规模 | 小型系统 | 中大型企业 | 超大型/云原生 | 协同办公平台 |
三、RBAC 的两大痛点深入解析
RBAC 是中流砥柱,解决了 80% 的企业级管理诉求,但它有两个著名的痛点。
痛点一:角色爆炸(Role Explosion)
本质
用静态的枚举(角色)去硬编码动态的多维组合,导致角色数量以笛卡尔积方式失控增长。
实例:医院电子病历系统
初始状态(3 个角色就够了):
医生、护士、管理员
引入业务维度后,安全部门要求细粒度管控:
| 维度 | 取值 |
|---|---|
| 科室 | 内科、外科、儿科 |
| 职级 | 主任医师、主治医师、住院医生 |
| 数据范围 | 全院、本科室、本病区 |
于是管理员开始"捏角色":
erlang
内科_主任医师_全院数据
内科_主任医师_本科室数据
内科_主治医师_本科室数据
外科_住院医生_本病区数据
...
仅 3 个维度 → 3 × 3 × 3 = 27 个角色
再加院区(3个)和项目(2个)→ 27 × 3 × 2 = 162 个角色
如果有 50 个细分病区 → 角色数突破数千个 💥
爆炸的四个成因
| 成因 | 说明 |
|---|---|
| 多维正交组合 | 权限取决于"你是谁 + 你在哪 + 你做什么 + 什么时间",强行枚举必然爆炸 |
| 缺乏继承机制 | 没有使用分层 RBAC,管理员直接复制基础角色改两三个权限,产生大量"克隆角色" |
| 用角色代替策略 | 把数据过滤条件硬编码成角色(如 北京区_销售经理),而不是抽象为数据权限策略 |
| 业务定制诉求 | 各部门要求"特例角色"(如"周末能看财务的临时审计员"),边缘角色越积越多 |
爆炸后的危害
- 管理失控:新员工入职面对几百个角色,根本不知道分配哪个
- 审计灾难:查"谁能删除数据库"需要遍历几百个角色,极易遗漏
- 权限冗余:废弃角色堆积,潜伏高危权限,甚至出现违反职责分离(SoD)的"毒性组合"
- 性能下降:登录时加载用户所有角色权限集,关联关系过多导致鉴权接口超时
解决方案
核心思路:分离功能权限和数据权限
功能权限(能不能做)→ 角色控制(按钮/菜单级别)
数据权限(能看哪些)→ 属性/策略控制(数据行/列级别)
用 ABAC 方式替代:不创建 北京区_高级_销售经理,只保留 销售经理,由策略引擎动态判断:
ini
IF User.Region == Resource.Region AND User.Level == 'Senior' THEN Allow
无论维度增加多少,角色数量始终保持在基础水平,复杂性转移到了策略引擎。
其他缓解措施:
- 分层 RBAC(RBAC1):利用角色继承减少重复配置
- 角色工程(Role Mining):算法分析实际权限集合,合并相似用户群为标准角色
- 生命周期管理:角色与组织架构绑定,入职自动分配,转岗自动回收
痛点二:缺乏上下文感知能力
本质
RBAC 是静态绑定的:角色一旦分配,权限就固定了,无论上下文怎么变,权限都不会自动调整。
实例
css
张医生 = [医生] 角色
→ 上午 10 点,医院内网,查看自己负责的患者 → ✅ 允许
→ 凌晨 2 点,家庭公网,查看无关患者病历 → ✅ 仍然允许!
RBAC 只看"你是不是医生",不看:
- 时间 --- 是否工作时间?
- 地点 --- 内网还是公共 WiFi?
- 关系 --- 是不是你的病人?
- 设备 --- 是否安装了安全证书?
- 行为 --- 是否异常操作?
这带来的现实问题
| 场景 | RBAC 的困境 |
|---|---|
| 零信任架构 | 零信任要求"持续验证每一次请求",RBAC 只能做一次性静态鉴权 |
| 远程办公 | 在家/在咖啡厅/在公司,权限应该不同,但 RBAC 一视同仁 |
| 敏感操作 | 删除数据库应要求"内网 + 工作时间 + MFA 通过",RBAC 做不到 |
| 跨部门协作 | "临时允许市场部小王本周查看产品部文档",RBAC 无法动态控制 |
解决方案
| 方案 | 思路 |
|---|---|
| ABAC 策略引擎 | 每次请求实时评估用户属性 + 资源属性 + 环境属性 |
| OPA(Open Policy Agent) | 策略即代码,支持复杂的环境上下文判断 |
| ReBAC(关系型) | 基于实体间图关系判断("你是不是这个文档的协作者") |
| 自适应授权 | 实时风险评分,动态调整权限(如 Okta Adaptive MFA) |
实际落地的混合方案
很多成熟系统采用 "RBAC 为骨架 + ABAC 为血肉" 的混合架构:
sql
┌──────────────────────────────────────────────────────┐
│ 鉴权决策层 │
│ │
│ 第一层:RBAC → 用户是否拥有该功能角色? │
│ (菜单/按钮级,静态,快) │
│ │
│ 第二层:ABAC → 当前上下文是否满足策略条件? │
│ (时间/IP/设备/关系,动态,细粒度) │
│ │
│ 第三层:数据过滤 → SQL 注入 WHERE 条件 │
│ (行/列级数据隔离) │
└──────────────────────────────────────────────────────┘
四、零信任架构深入解析
从"城堡护城河"到"零信任"
传统模型的问题
传统安全基于"城堡与护城河"范式 --- 防火墙以内被视为安全区域,一旦突破边界,内部资源几乎不受限制:
┌──────────────────────────────────────────┐
│ 互联网(不可信) │
│ │
│ ╔═══════════════════╗ │
│ ║ 防火墙(护城河) ║ │
│ ╚═══════════════════╝ │
│ │
│ ┌───────────────────┐ │
│ │ 内网(完全可信) │ │
│ │ │ │
│ │ 一旦进来,畅通无阻 │ │
│ │ ↗ 横向移动无限制 │ │
│ └───────────────────┘ │
└──────────────────────────────────────────┘
这种模型已经失效:
| 挑战 | 说明 |
|---|---|
| 云和远程办公 | 企业网络边界模糊化,员工可以在任何地方办公 |
| 内部威胁 | 约 43% 的安全事件源自内部,防火墙挡不住"自己人" |
| 移动/IoT 设备 | 大量不受控设备接入网络 |
| 横向移动 | 攻击者一旦突破边界,就可以在内网自由移动 |
零信任的核心信条
dart
❌ 传统: "内网 = 可信,外网 = 不可信"
✅ 零信任: "从不信任,始终验证" (Never Trust, Always Verify)
NIST 定义的三大核心原则
根据 NIST SP 800-207 标准:
| 原则 | 说明 |
|---|---|
| 始终验证 | 每次访问请求都要认证+授权,不做任何"免检"假设 |
| 最小权限 | 只授予完成任务所需的最低限度权限,遵循 JIT(即时授权)和 JEA(适度授权) |
| 假设失陷 | 假设网络中已经存在威胁,通过微隔离限制横向移动 |
补充机制:
- 持续验证 --- 信任不是一次性的,整个会话期间持续评估
- 动态授权 --- 基于实时上下文动态调整权限
- 微隔离 --- 将网络切分为细粒度区域,封锁横向移动路径
架构组件
scss
┌─────────────────────────────────────────────────────┐
│ │
│ 策略引擎(PE) │
│ Policy Engine --- 决策大脑 │
│ 收集身份、设备、上下文 → 计算信任分数 → 做出访问决策 │
│ │
└──────────────────────┬──────────────────────────────┘
│ 访问决策 (Allow / Deny / Step-up)
▼
┌─────────────────────────────────────────────────────┐
│ │
│ 策略执行点(PEP) │
│ Policy Enforcement Point │
│ 在网络连接中实际执行策略,控制数据流 │
│ (API网关、反向代理、微隔离模块) │
│ │
└──────────┬──────────────────────────────┬───────────┘
│ │
┌─────▼─────┐ ┌─────▼─────┐
│ 用户 │ ←── 访问 ──→ │ 应用/资源 │
│ (Subject) │ │ (Resource) │
└───────────┘ └───────────┘
辅助组件:
┌────────────┐ ┌────────────┐ ┌────────────┐
│ 身份提供者 │ │ 威胁情报源 │ │ 日志/监控 │
│ (IdP) │ │ │ │ (SIEM) │
└────────────┘ └────────────┘ └────────────┘
| 组件 | 角色 | 类比 |
|---|---|---|
| 策略引擎(PE) | 决策大脑,评估请求并做出访问决策 | 保安队长 |
| 策略执行点(PEP) | 在网络层实施访问控制 | 门口的闸机 |
| 身份提供者(IdP) | 管理用户/设备身份,提供认证(SAML/OIDC) | 身份证发放机构 |
| 威胁情报源 | 提供外部安全威胁信息 | 公安通缉令 |
| SIEM | 收集所有访问日志,分析和告警 | 监控中心 |
信任评估模型 --- 零信任的"灵魂"
零信任引入了**信任分数(Trust Score)**机制,动态计算访问主体的可信度:
ini
Trust Score = f(身份置信度, 设备安全状态, 网络环境, 行为基线, 威胁情报)
实际场景示例:
yaml
张工访问财务系统:
上午 10 点,公司内网,公司笔记本,正常操作模式
→ Trust Score: 92/100 → ✅ 完全访问
凌晨 2 点,家庭WiFi,个人手机,从未有过此类访问
→ Trust Score: 35/100 → ❌ 拒绝访问 / 要求额外验证
上午 11 点,咖啡厅WiFi,公司笔记本
→ Trust Score: 65/100 → ⚠️ 降级权限,仅允许只读
决策矩阵:
| 分数区间 | 处置方式 |
|---|---|
| ≥ 80 分 | 完全访问权限 |
| 50 ~ 79 分 | 受限访问 / 要求 MFA |
| < 50 分 | 拒绝访问 / 要求重新认证 |
典型访问请求流程
markdown
用户发起访问请求
│
▼
① PEP 拦截请求
│
▼
② PE 收集上下文信息
├── 身份认证(MFA 多因素)
├── 设备健康检查(补丁版本、杀毒软件状态)
├── 地理位置 / 网络环境评估
└── 行为基线比对(是否异常)
│
▼
③ PE 做出访问决策
├── ✅ 授予访问 → PEP 放行
├── ❌ 拒绝访问 → PEP 阻断
└── ⚠️ 条件授权 → 降级权限 / 要求额外验证
│
▼
④ 持续监控会话(不是一次性的!)
├── 行为异常检测
├── 设备状态变化监控
└── 动态调整权限(随时可以收紧或放开)
关键差异:传统模型在第 ① 步就结束了(一次性认证),零信任的第 ④ 步是持续进行的。
零信任与权限模型的关系
零信任不是一个独立的权限模型,而是一个安全架构框架,它需要组合使用多种权限模型:
┌─────────────────────────────────────────────────────┐
│ 零信任架构 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ RBAC │ │ ABAC │ │ ReBAC │ │
│ │ 基础角色 │+│ 动态策略 │+│ 关系判断 │ │
│ │ 功能权限 │ │ 上下文 │ │ 资源协作 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ + 信任分数评估 + 持续验证 + 微隔离 │
└─────────────────────────────────────────────────────┘
| 层 | 权限模型 | 在零信任中的角色 |
|---|---|---|
| 功能权限 | RBAC | 用户是否拥有该角色的基本访问权 |
| 动态策略 | ABAC | 当前上下文(时间/设备/IP)是否满足条件 |
| 资源关系 | ReBAC | 用户与资源之间是否存在允许访问的关系 |
| 信任评估 | 零信任独有 | 综合信任分数是否达标 |
传统模型 vs 零信任
| 维度 | 传统模型 | 零信任 |
|---|---|---|
| 信任假设 | 内网可信 | 永不信任 |
| 防御边界 | 网络边界(防火墙) | 每个资源/身份 |
| 访问控制 | 基于网络位置 | 基于身份 + 上下文 |
| 权限粒度 | 粗粒度(网段级) | 细粒度(应用/数据级) |
| 验证频率 | 一次性认证 | 持续验证 |
| 横向移动 | 容易(边界内畅通) | 困难(微隔离) |
实施路径(渐进式)
零信任不是一蹴而就的,通常分五个阶段推进:
阶段一:身份管理
→ 部署 MFA、统一身份管理(IAM)、SSO
阶段二:设备安全
→ 设备健康评估、终端安全代理
阶段三:网络微隔离
→ 细分网络区域、限制东西向流量
阶段四:应用与数据安全
→ 应用级访问控制、数据加密与分类
阶段五:持续监控与优化
→ SOC 安全运营中心、策略持续优化
五、从 ACL 到零信任:五次思维跃迁
权限系统的演进不仅仅是技术升级,更是思维方式的根本转变。
第一次跃迁:ACL → RBAC --- 从枚举到抽象
核心问题:用户和权限越来越多,一条条配置配不过来了。
css
ACL 的思维:
文件A → 张三[读]、李四[读写]
文件B → 张三[读写]、王五[读]
... 几百个文件,几千个用户 → 灾难
RBAC 的思维:
管理者 → 赋予 [读/写/删] 权限
张三 = 管理者 → 自动拥有 读/写/删
转变:不再逐个列举,而是找到共性归类。用"角色"这个中间层,把 M×N 的网状关系简化为树状结构。
scss
之前:User × Permission 的网状关系(O(m×n))
之后:User → Role → Permission 的链式关系(O(m+n))
本质:管理复杂度的优化 --- 解决"怎么管好"的管理学问题。
第二次跃迁:RBAC → ABAC --- 从枚举身份到描述属性
核心问题:角色越来越多,已经"爆炸"了。
vbnet
RBAC 的困境:
"北京区的销售经理只能看北京的订单" → 角色:北京区销售经理
"上海的也要看" → 再加:上海区销售经理
"高级经理能看全部" → 再加:高级_北京区销售经理...
→ 💥
ABAC 的思路:
不创建角色,写一条策略:
IF User.Region == Order.Region THEN Allow
→ 一条策略覆盖所有情况
转变:不再问"你是什么角色",而是问"你具有什么特征"。权限不再提前分配好,而是在每次访问时实时计算。
本质:表达能力的跃迁 --- 用有限数量的策略规则覆盖无限数量的场景。
第三次跃迁:ABAC → ReBAC --- 从个体特征到关系网络
核心问题:ABAC 擅长描述"属性",但不擅长描述"关系"。
css
ABAC 的困境:
"我能编辑这个文档" --- 为什么?
→ 因为我是这个文件夹的编辑者
→ 因为这个文件夹属于我的团队
→ 因为团队负责人把这个文件夹共享给了我
这种"层层传递"的关系链,用 ABAC 描述非常笨拙。
ReBAC 的思路:
直接建模关系图:
User →[是编辑者]→ Folder →[属于]→ Team →[包含]→ Document
权限 = 在关系图中是否存在一条允许的路径
转变:权限不仅取决于"你是谁",更取决于"你和资源之间的社会关系"。权限决策从一次查表变成了一次图搜索,且权限可以沿关系链传递。
本质:建模维度的扩展 --- 引入了"关系"这个被长期忽略的维度。
第四次跃迁:从权限模型 → 零信任架构 --- 从静态信任到持续验证
核心问题:前面所有模型都隐含一个假设 --- "信任是稳定的"。
arduino
传统模型的隐含假设:
登录时验证身份 → ✅ 通过 → 获得权限 → 之后一路畅通
问题:
- 登录的是合法用户,但后来设备中了病毒呢?
- 用户从公司内网切到了咖啡厅 WiFi 呢?
- 用户的行为模式突然变了(凌晨3点批量下载)呢?
零信任的思路:
登录时验证 → ✅ → 每5秒/每次请求都在验证 → 随时收紧或切断
信任不是"开关",而是"水龙头" --- 可以实时调节大小
转变:
| 维度 | 之前 | 之后 |
|---|---|---|
| 信任模型 | 二元(信任/不信任) | 连续(信任分数) |
| 防御策略 | 边界防御(坚固外壳) | 纵深防御(层层检查) |
| 授权方式 | 静态(一次性事件) | 动态(持续过程) |
| 关注焦点 | 你是谁 | 你正在做什么 |
本质:信任哲学的根本转变 --- 不再假设"管好了就安全",而是假设"随时可能被攻破"。
五条演进主线
| 维度 | 演进方向 | 一句话概括 |
|---|---|---|
| 信任模型 | 朴素信任 → 组织信任 → 条件信任 → 关系信任 → 零信任 | 信任越来越"不信任" |
| 控制粒度 | 资源级 → 角色级 → 属性级 → 关系级 → 请求级 | 从"粗管"到"微操" |
| 时间维度 | 一次性 → 一次性 → 每次请求 → 每次请求 → 整个会话 | 从"一次验证"到"持续验证" |
| 决策方式 | 查表 → 查表 → 策略计算 → 图遍历 → 综合评估 | 从静态到动态,从离散到连续 |
| 建模对象 | 资源 → 人 → 属性 → 关系 → 上下文 | 关注的维度越来越多 |
最深层的思维转变
如果用一句话概括整个演进的本质:
从"管理复杂性"到"对抗不确定性"
第一层(ACL/RBAC):如何高效地分配权限? ← 管理学问题
第二层(ABAC/ReBAC):如何精确地描述权限? ← 建模问题
第三层(Zero Trust):如何假设一切都不安全? ← 哲学问题
六、选型建议速查
| 项目类型 | 推荐方案 | 理由 |
|---|---|---|
| 初创项目 / 简单后台 | RBAC | 开发成本最低,能快速满足"不同岗位看不同菜单"的需求 |
| 多租户 SaaS | RBAC + 数据权限过滤 | RBAC 管功能菜单,SQL 拦截器注入 WHERE tenant_id = ? 做数据隔离 |
| 协同办公 / 知识库 | RBAC(系统级)+ ReBAC(资源级) | 系统管理用 RBAC,文档共享/继承/协作用 ReBAC |
| 零信任 / 云原生平台 | ABAC(结合 OPA 策略引擎) | 结合设备环境、用户行为、资源标签做动态风控 |
| 大型政企 | RBAC + ABAC + 零信任 | 分阶段实施,渐进式演进 |
七、总结
权限系统的演进是一部"信任不断被质疑"的历史:
- ACL 回答了"谁能访问什么",但管不过来
- RBAC 用角色解决了管理效率问题,但角色会爆炸
- ABAC 用策略解决了灵活性和上下文感知,但设计复杂
- ReBAC 用关系图解决了协作和继承问题,但需要专用引擎
- 零信任 把一切归零 --- 不信任任何人,每次都验证,持续监控
没有银弹,只有权衡。 实际落地中,通常是多种模型的组合拳:RBAC 做骨架保证开发效率,ABAC 做血肉保证灵活性,零信任做免疫系统保证安全底线。
选型的终极原则:不是选最先进的,而是选最适合当前业务阶段的。
参考资料:NIST SP 800-207《零信任架构》、NIST SP 800-162《基于属性的访问控制指南》、Google Zanzibar 论文、Forrester ZTX 框架