跳到内容

第 8 卷 / 第 3 章 / 第 3 课

3.3 授权模型:RBAC、ABAC、ReBAC 与资源级检查 ​

认证确认主体,授权决定主体在当前上下文能对具体资源执行什么动作。很多越权漏洞并不是没有登录,而是应用只检查“已登录”或“拥有某角色”,没有检查目标对象与主体之间的关系。

一次决策至少有四个输入 ​

text
allow? = policy(subject, action, resource, context)
  • subject:用户、服务、设备及其组织、角色、认证保证;
  • action:read、update、approve、transfer,而不只是 HTTP method;
  • resource:具体订单、项目、字段、租户与当前状态;
  • context:时间、网络、设备风险、变更窗口和请求来源。

安全默认是 deny。没有匹配允许规则、策略数据缺失、策略引擎超时或身份不确定时,都不应悄悄放行高风险操作。

RBAC 管理稳定的工作职责 ​

text
user → role → permissions

RBAC 适合“审计员可读报告”“发布经理可批准发布”一类稳定职责。角色应表达业务责任,而不是每个页面创建一个角色。若出现 admin-east-read-except-finance-temp 这类组合爆炸,说明还需要属性或关系。

避免把 admin 写成绕过所有授权的布尔值。高权限操作也应有明确 action、范围、重新认证和审计,并允许拆分日常账户与临时提权会话。

ABAC 用属性表达动态约束 ​

ABAC 可以组合:

text
subject.department == resource.department
AND resource.classification <= subject.clearance
AND context.time within approved_window

上例的密级与许可等级必须有明确定义的顺序,不能直接按字符串字典序比较。属性本身需要可信来源、类型、时效和所有者。若用户能修改自己的 department claim,策略再漂亮也没有意义。策略语言应有测试、变更评审和可解释决策日志,避免散落在几十个 controller 的条件分支中。

ReBAC 描述主体与对象关系 ​

协作文档、代码仓库和社交产品常依赖关系:

text
user:lin is member of team:atlas
team:atlas is editor of project:north
rule: project editors may edit documents belonging to that project
therefore user:lin can edit document:x in project:north

ReBAC 能表达继承、共享与组织图,但需要控制图遍历深度、循环、缓存一致性和关系撤销延迟。把对象 ID 从 17 换成 UUID 只能降低枚举便利,不能替代每次资源访问的关系检查。

IDOR/BOLA 来自缺失的资源级授权 ​

危险流程:

text
GET /orders/8172
→ 验证用户已登录
→ SELECT * FROM orders WHERE id = 8172
→ 返回

安全查询应尽早把授权范围纳入数据访问:

sql
SELECT id, tenant_id, owner_id, status
FROM orders
WHERE id = :order_id
  AND tenant_id = :principal_tenant
  AND owner_id = :principal_id;

更复杂权限可先由 policy engine 得出允许范围或关系,再查询对象。无论采用哪种架构,列表、详情、更新、导出、批量接口和后台任务都要执行一致检查。前端隐藏按钮可以提示界面权限,但不能阻止直接发送请求。

让相同对象编号落在不同租户 ​

下例用 SQLite 内存库执行相同的参数化查询,只实现“所属租户且本人拥有”的读取规则。principal_tenant 与 principal_id 必须来自服务端已验证的主体上下文;函数参数不会自动变可信,不能把请求体的自报值直接传进来。

python
import sqlite3

db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE orders (id INTEGER, tenant_id TEXT, owner_id INTEGER, status TEXT)")
db.executemany("INSERT INTO orders VALUES (?, ?, ?, ?)", [
    (8172, "north", 101, "open"),
    (8173, "north", 102, "open"),
    (8172, "south", 101, "open"),
])

def read_order(order_id, principal_tenant, principal_id):
    return db.execute("""
        SELECT id, tenant_id, owner_id, status FROM orders
        WHERE id = :order_id
          AND tenant_id = :principal_tenant
          AND owner_id = :principal_id
    """, {"order_id": order_id, "principal_tenant": principal_tenant,
          "principal_id": principal_id}).fetchone()

assert read_order(8172, "north", 101) == (8172, "north", 101, "open")
assert read_order(8173, "north", 101) is None
assert read_order(8172, "south", 102) is None
assert read_order(8172, "west", 101) is None
assert read_order(9999, "north", 101) is None
db.close()

把 tenant 条件删除,再测试不同租户的同号对象;把 owner 条件删除,再测试同租户其他用户的对象。更新和审批还需将对象状态与权限条件放进同一原子写入或事务,避免“检查时允许、执行时已撤权”的竞态。

多租户边界应贯穿全链路 ​

Tenant 不能只来自客户端 header。用户可切换多个租户时,服务端必须验证其对所选租户的成员资格和当前操作权限。应从已验证身份和服务端路由上下文确定租户,并在数据库查询、缓存 key、对象存储 path、队列消息、搜索索引和日志访问中传播。

缓存若只用 resource_id,可能把 A 租户对象返回给 B;后台 worker 若信任消息中的 tenant 而不验证任务签发者,也会跨边界执行。租户隔离是数据模型与执行上下文属性,不是 API gateway 的一个过滤器。

Confused Deputy:有权限的服务被借来做坏事 ​

某个转换服务有权读取所有对象,用户提交任意 source_url 后让它代读内部管理地址,这个服务就成了 confused deputy。防护包括:

  • 代表用户调用下游时传递或换取受限 delegated credential;
  • 将 audience、resource、action 和租户绑定到 token;
  • 服务自身权限与代表用户的权限取交集;
  • 不接受任意资源引用,使用服务端解析与 allowlist;
  • 对跨边界操作保留原始主体链和审计。

策略集中不等于单点远程调用 ​

可以把策略定义集中到版本化 policy repository,同时根据延迟与可用性选择 sidecar、嵌入式 evaluator 或本地缓存。必须明确:

  • policy decision point 不可用时哪些动作 fail closed;
  • policy 和关系数据多久传播,撤权窗口多长;
  • 缓存是否覆盖主体、资源、动作、tenant、策略/关系版本和实际影响决策的上下文,且 TTL 不超过允许的撤权窗口;
  • 决策日志是否记录输入摘要、规则版本和结果,又避免泄露秘密;
  • 紧急 deny 是否有比普通发布更快的分发路径。

高风险动作还可使用 just-in-time elevation:短期、限定资源、需要审批,过期自动撤销。永久超级管理员既扩大攻击面,也让审计很难区分日常与紧急操作。

授权测试矩阵 ​

text
正向:正确主体可以执行允许动作
横向:同角色用户不能访问未获授权的其他用户资源
纵向:普通用户不能执行高权限动作
跨租户:任何资源引用都不能越过 tenant
状态:已关闭/冻结对象拒绝原本允许的动作
撤权:关系或角色撤销后,在约定窗口内生效
故障:策略服务/属性源不可用时按设计失败
批量:列表、导出和异步任务与单对象检查一致

认证强度再高,也不会自动产生正确授权。把资源级检查放进服务端可信边界,并让策略可测试、可解释、可撤销,才是权限系统真正的基础。

参考资料 ​

Built with VitePress | Software Systems Atlas