第十三章:访问控制模型

“授权的本质是回答一个问题:主体 S 能否对客体 O 执行操作 A?”

        mindmap
  root((访问控制模型))
    DAC
      文件权限
      ACL
    MAC
      Bell-LaPadula
      SELinux
    RBAC
      角色
      层次
      约束
    ABAC
      属性
      策略
      XACML
    ReBAC
      Zanzibar
      关系元组
      图遍历
    

13.1 访问控制基本概念

访问控制的核心要素:

┌──────────┐    ┌──────────┐    ┌──────────┐
│  主体(S)  │───▶│  操作(A)  │───▶│  客体(O)  │
│ Subject   │    │ Action    │    │ Object    │
│ 用户/服务 │    │ 读/写/删  │    │ 文件/API  │
└──────────┘    └──────────┘    └──────────┘
                     │
                     ▼
              ┌──────────┐
              │  策略(P)  │
              │ Policy    │
              │ 允许/拒绝 │
              └──────────┘

13.2 DAC — 自主访问控制

DAC(Discretionary Access Control)由资源拥有者决定谁可以访问。最典型的例子是 Unix 文件权限:

# Unix 文件权限
-rwxr-xr-- 1 alice developers 4096 Jan 1 00:00 report.txt
│├─┤├─┤├─┤
│     └── 其他用户:只读
│   └───── (developers):读+执行
│ └──────── 拥有者(alice):读+写+执行
└────────── 文件类型

# ACL(访问控制列表)— 更细粒度
setfacl -m u:bob:rw report.txt    # 给 bob 读写权限
setfacl -m g:audit:r report.txt   # 给 audit 组只读权限
getfacl report.txt                 # 查看 ACL

优点:简单直观、灵活 缺点:难以集中管理、容易权限蔓延

13.3 MAC — 强制访问控制

MAC(Mandatory Access Control)由系统强制执行安全策略,用户无法更改。

Bell-LaPadula 模型(保密性)

安全级别:绝密 > 机密 > 秘密 > 公开

规则:
• No Read Up(简单安全属性):不能读高于自己级别的数据
• No Write Down(*属性):不能写低于自己级别的数据

┌──────────┐
│  绝密     │  ← 绝密用户可读写
│          │  ← 机密用户不能读(No Read Up)
├──────────┤
│  机密     │  ← 机密用户可读写
│          │  ← 绝密用户不能写(No Write Down)
├──────────┤
│  秘密     │
├──────────┤
│  公开     │
└──────────┘

SELinux

# 查看 SELinux 上下文
ls -Z /var/www/html/index.html
# system_u:object_r:httpd_sys_content_t:s0 index.html

# SELinux 策略:httpd 进程只能访问 httpd_sys_content_t 类型的文件
# 即使 httpd 被攻破,也无法访问其他类型的文件

13.4 RBAC — 基于角色的访问控制

RBAC(Role-Based Access Control)通过角色间接授权:

用户 ──▶ 角色 ──▶ 权限

┌──────┐    ┌──────────┐    ┌──────────────┐
│ Alice │───▶│  Admin   │───▶│ user:read    │
│      │    │          │    │ user:write   │
└──────┘    └──────────┘    │ user:delete  │
                            │ config:write │
┌──────┐    ┌──────────┐    └──────────────┘
│ Bob  │───▶│  Editor  │───▶│ doc:read     │
│      │    │          │    │ doc:write    │
└──────┘    └──────────┘    └──────────────┘

┌──────┐    ┌──────────┐    ┌──────────────┐
│Carol │───▶│  Viewer  │───▶│ doc:read     │
└──────┘    └──────────┘    └──────────────┘

RBAC 层次

from enum import Enum
from dataclasses import dataclass, field

class Permission(Enum):
    READ = "read"
    WRITE = "write"
    DELETE = "delete"
    ADMIN = "admin"

@dataclass
class Role:
    name: str
    permissions: set[Permission]
    parent: 'Role | None' = None  # 层次 RBAC

    def has_permission(self, perm: Permission) -> bool:
        if perm in self.permissions:
            return True
        if self.parent:
            return self.parent.has_permission(perm)
        return False

# 角色层次:Admin > Editor > Viewer
viewer = Role("viewer", {Permission.READ})
editor = Role("editor", {Permission.WRITE}, parent=viewer)
admin = Role("admin", {Permission.DELETE, Permission.ADMIN}, parent=editor)

assert admin.has_permission(Permission.READ)    # 继承自 viewer
assert admin.has_permission(Permission.WRITE)   # 继承自 editor
assert admin.has_permission(Permission.DELETE)   # 自身权限
assert not viewer.has_permission(Permission.WRITE)  # 无此权限

RBAC 的局限性

问题

描述

角色爆炸

细粒度需求导致角色数量指数增长

缺乏上下文

无法表达”只在工作时间访问”

资源级控制弱

难以表达”只能访问自己的文档”

动态权限难

权限变更需要修改角色定义

13.5 ABAC — 基于属性的访问控制

ABAC 基于属性做出授权决策,更加灵活:

ABAC 决策过程:
┌──────────────────────────────────────────────┐
│  主体属性        │ 角色=editor, 部门=engineering │
│  资源属性        │ 类型=document, 密级=internal  │
│  操作属性        │ 动作=edit                     │
│  环境属性        │ 时间=工作日, IP=内网           │
├──────────────────┴──────────────────────────────┤
│  策略:                                          │
│  IF 主体.角色 == "editor"                        │
│  AND 资源.密级 <= "internal"                     │
│  AND 环境.时间 IN 工作时间                        │
│  AND 环境.IP IN 内网范围                          │
│  THEN 允许 edit                                  │
└──────────────────────────────────────────────────┘

RBAC vs ABAC 对比

维度

RBAC

ABAC

授权依据

角色

属性(多维度)

粒度

粗粒度

细粒度

灵活性

复杂度

上下文感知

动态策略

困难

容易

审计

简单

复杂

适用规模

中小型

大型

13.6 ReBAC — 基于关系的访问控制

ReBAC(Relationship-Based Access Control)基于实体之间的关系做出授权决策。Google 在 2019 年发表的 Zanzibar 论文奠定了 ReBAC 的基础。

Google Zanzibar

Zanzibar 是 Google 内部的全球授权系统,服务于 Google Drive、YouTube、Cloud 等产品。

核心概念 — 关系元组(Relation Tuple)

格式:object#relation@subject

示例:
document:budget#reader@user:alice
  → alice 是 budget 文档的 reader

document:budget#reader@group:finance#member
  → finance 组的所有 member 都是 budget 文档的 reader

folder:engineering#viewer@folder:root#viewer
  → root 文件夹的 viewer 也是 engineering 文件夹的 viewer(继承)

为什么 ReBAC 是未来趋势

RBAC 的问题:
"Alice 能编辑文档吗?" → 只能回答"能"或"不能"
无法区分"Alice 能编辑哪些文档"

ReBAC 的优势:
"Alice 能编辑文档 X 吗?" → 检查 Alice 与文档 X 的关系
"Alice 能编辑哪些文档?" → 遍历 Alice 的所有关系

关系图:
user:alice ──reader──▶ document:budget
user:alice ──member──▶ team:engineering
team:engineering ──parent──▶ org:acme
org:acme ──viewer──▶ folder:shared
folder:shared ──parent──▶ document:roadmap
→ Alice 可以查看 roadmap(通过关系链推导)

13.7 访问控制模型对比

模型

授权依据

粒度

复杂度

适用场景

DAC

资源拥有者决定

文件系统

MAC

安全标签

军事/政府

RBAC

角色

企业应用

ABAC

属性

复杂策略

ReBAC

关系

协作应用、SaaS

选型决策树

你的授权需求是什么?
│
├── 简单的角色权限?
│   └── ✅ RBAC(大多数应用的起点)
│
├── 需要上下文感知?(时间、位置、设备)
│   └── ✅ ABAC(OPA/Cedar)
│
├── 需要资源级别的细粒度控制?
│   ├── 资源之间有层次/继承关系?
│   │   └── ✅ ReBAC(OpenFGA)
│   └── 基于属性的条件?
│       └── ✅ ABAC + ReBAC 组合
│
└── 以上都需要?
    └── ✅ ReBAC(OpenFGA)+ ABAC(OPA)组合

13.8 小结

  • DAC 简单但难以集中管理,适合文件系统

  • MAC 安全性最高但灵活性最低,适合军事/政府

  • RBAC 是最普及的模型,但存在角色爆炸和粒度不足的问题

  • ABAC 通过多维属性实现细粒度控制,但策略管理复杂

  • ReBAC 基于 Google Zanzibar,通过关系图实现直观的细粒度授权

  • 实际项目中,RBAC + ReBACRBAC + ABAC 的组合是最常见的选择