Archipelago

Lec 18特权分离(Privilege Separation)

讲义完成更新于 2026-09-16

Lec 18 特权分离(Privilege Separation)

MIT 6.1600 · Introduction to Computer Security

TL;DR

  • 特权分离从“组件终会被攻破”出发,把系统拆成仅持最小权限的进程或服务,使单点失陷不会直接获得全部能力。
  • 边界应隔离高风险解析器、长期密钥和高价值数据;跨边界接口必须同时足够完成任务、足够窄以限制被攻破调用方。
  • OpenSSH、浏览器和支付系统说明分离可以显著缩小损害范围,但更多组件与 RPC 也增加状态同步、性能和接口漏洞成本。

1. 核心思想

软件必然存在 bug,单纯消除 bug 难以实现。另一策略:

规划妥协(Plan for Compromise)——假设某个组件会被攻破,通过架构设计限制损害范围。

最小权限原则(Principle of Least Privilege):

每个组件只应拥有完成其工作所必需的最小权限集合。

该原则是难以完全达到的设计目标,而非硬性规则——在安全性与复杂度之间权衡。

2. 实施挑战

2.1 边界划分(Splitting Boundaries)

将大型软件划分为组件时,需找到合适的边界:

划分方式示例
按用户隔离OS 中不同用户的账号
按功能分割大型业务系统中搜索/用户/邮件作为独立服务
隔离高风险代码Firefox 将视频 Codec 放入沙箱
前端与核心隔离Google 前端 HTTP 服务器与内部数据库服务器分离
密钥隔离CA 用 HSM 隔离签名密钥与其他代码

2.2 接口设计(Interface/API)

组件间交互 API 必须:

  • 功能完整:允许合法操作
  • 安全限制:防止组件 A 被攻破后危害组件 B
  • 低性能开销:隔离不能使系统无法使用
  • 低复杂度:接口代码本身不引入新漏洞

接口实现方式:RPC(远程过程调用)、消息队列、共享内存、共享数据库、共享文件。

3. 实例:日志系统

目标:攻击者攻破应用服务器后无法删除审计日志。

架构:

应用服务器 ---[仅追加]---> 日志服务器 ----> 日志存储
              (Append/Read API, 无 Delete)
  • 应用服务器只能追加日志,不能删除
  • 即使应用服务器被攻破,攻击者仍无法抹除历史日志

4. 实例:密钥管理

目标:即使应用被攻破,攻击者无法提取签名私钥。

架构:

应用 ---[sign(msg) / get_public_key()]--> 密钥管理器(含 sk)
       (没有提取 sk 的 API)

攻击者即使控制了应用,也只能调用 sign(),不能提取 sk。

可以在密钥管理器中增加策略:只签名符合格式的消息,限制攻击者伪造的范围。

同时密钥管理器记录所有签名操作日志,为事后取证提供证据。

5. 实例:Firefox 媒体 Codec 沙箱

JPEG 等媒体 Codec 历史上漏洞频发,是浏览器攻击的常见入口。

架构(WebAssembly 语言级隔离):

浏览器 Tab ---[编码数据]--> Codec 沙箱
             <---[位图]----
  • Codec 在独立的 WebAssembly 沙箱中运行
  • 若恶意图片触发 Codec 漏洞,攻击者只能访问 Codec 进程的内存,无法直接访问用户 Cookie 等数据

API 设计挑战:视频解码是增量的(Progressive)——接口设计需同时支持流式解码和低延迟,避免引入新漏洞。

6. 实例:NTP 客户端(操作系统时间服务)

设置系统时间需要 root 权限,但 NTP 代码需要复杂的网络处理(易有 bug)。

架构:

网络 <---> NTP 网络进程(无 root)
               |
          [adjust clock]
               ↓
           时间服务(有 root,执行策略)
  • 网络代码 bug 只允许攻击者影响时间,不能执行任意 root 操作
  • 时间服务可加策略(如时间不能倒退)

7. 实例:OpenSSH 服务器

SSH 服务器需要访问:网络端口 22、主机签名密钥、密码数据库、用户文件。

架构:

[ 主机密钥 ] [ 密码 DB ] [ 端口 22 ]
      |
      ↓
   Monitor 进程(持有所有权限)
      |
      ├── 每个连接生成 Worker 进程
      |   (无密钥、无密码 DB 访问)
      |   ↕ 通过有限 API 与 Monitor 通信
      |
      └── 认证成功后创建 Session 进程

Worker 与 Monitor 的 API:

  • sign(transcript) — 请求 Monitor 用主机密钥签名
  • check_password(user, pw) — 密码验证(Monitor 可限速)
  • start_session(user) — 创建 Shell 进程

网络层漏洞最多让攻击者控制 Worker,不能直接获取主机密钥或密码数据库。

8. 实例:Web 服务架构

Client --TLS--> [前端 HTTPS 服务器,持有 TLS 密钥]
                    |
                    +---> [Login 服务] <--> [密码 DB]
                    |
                    +---> [Profile 服务] <--> [用户 DB]
                    |
                    +---> [Photo 服务] <--> [Photo DB]
  • 各后端服务只有各自 DB 的访问权
  • 前端服务器隔离 TLS 密钥与业务逻辑
  • Login 服务被攻破 → 仅影响密码 DB,不影响 Photo DB

9. 实例:浏览器与 Web 客户端

Gmail PDF 附件:通过 googleusercontent.com 域名提供,与 google.com 不同 Origin:

  • Same-Origin Policy 防止 googleusercontent.com 的代码读取 google.com 的 Cookie
  • 即使 PDF 触发漏洞,攻击者代码无法直接偷取 Google 账号 Cookie

浏览器多进程架构:

Codec 沙箱 <--> mit.edu 进程
Codec 沙箱 <--> nytimes.com 进程
                  |
             浏览器核心 <--> UI <--> GPU
                  |
              [Cookies, 缓存]

完全攻破浏览器需要同时利用多个组件的漏洞。

10. 实例:支付系统

在线商户将信用卡数据完全外包给支付处理商:

Client --[商品选择]--> 商户网站
              |
              ↓(重定向到支付页)
Client --[信用卡数据]--> 支付处理商 ---> Visa/MC
              |
              ↓(支付完成,重定向回商户)
商户收到支付确认,但从不接触信用卡数据

商户系统被攻破也无法获取信用卡信息——数据从未到达商户服务器。

关键原则总结

最小权限+隔离边界+窄接口=局部损害,全局安全\boxed{\text{最小权限} + \text{隔离边界} + \text{窄接口} = \text{局部损害,全局安全}}

设计决策安全收益
功能按最小权限拆分单组件失陷不影响整体
窄且严格的组件间 API减少跨组件攻击面
密钥/凭据单独隔离防止应用层攻击窃取凭据
只追加日志防止攻击者销毁证据
前端/后端隔离暴露在互联网的代码攻破面最小化

我的理解

最小权限只有与最小接口同时实施才有效;拆分进程却保留宽泛 IPC,仍会把高权限能力暴露给低信任代码。