MIT 6.858 计算机系统安全讲义 2014 秋季(一)(3)https://developer.aliyun.com/article/1484146
回到 OKWS:他们的应用/动机是什么?
- 约会网站:担心数据保密性。
- 不太担心对手闯入并发送垃圾邮件。
- 大量的服务器端代码执行:匹配,配置文件更新,…
- 必须在用户之间共享(例如匹配)-- 不能只是分区。
- 对整体计划的良好总结:
- “最容易受攻击的方面对攻击者最无用”
为什么这么难?
- Unix 使降低权限变得棘手(chroot,UID,…)
- 应用程序需要以复杂的方式共享状态。
- Unix 和 SQL 数据库没有细粒度的共享控制机制。
OKWS 如何分割 Web 服务器?
- 论文中的图 1。
- 这个 Web 服务器中的请求是如何流动的?
okd -> oklogd
-> pubd
-> svc -> dbproxy
-> oklogd
- 这种设计如何映射到物理机器?
- 可能有许多前端机器(
okld
,okd
,pubd
,oklogd
,svc
) - 几台 DB 机器(
dbproxy
,DB)
这些组件如何互动?
okld
为每个服务设置socketpair
s(双向管道)。
- 一个用于控制 RPC 请求的套接字对(例如,“获取新的日志套接字对”)。
- 用于日志记录的一个套接字对(
okld
首先通过 RPC 从oklogd
获取它)。 - 对于 HTTP 服务:一个用于转发 HTTP 连接的套接字对。
- 对于
okd
:HTTP 服务的套接字对的服务器端 FD(HTTP+RPC)。
okd
监听一个单独的套接字以接收控制请求(repub,relaunch)。
- 在图 1 中似乎是端口 11277,但在 OKWS 代码中是 Unix 域套接字。
- 对于repub,
okd
与pubd
通信以生成新模板,
- 然后通过 RPC 控制通道将生成的模板发送给每个服务。
- 服务通过 TCP 与 DB 代理通信(通过端口号连接)。
OKWS 如何在图 1 中的组件之间强制隔离?
- 每个服务作为单独的 UID 和 GID 运行。
- chroot 用于将每个进程限制在单独的目录中(几乎)。
- 组件通过管道(或者说 Unix 域套接字对)进行通信。
- 用于传递 HTTP 连接的文件描述符传递。
okld
的目的是什么?- 为什么
okld
不同于okd
? - 为什么
okld
需要以 root 身份运行?(端口 80,chroot/setuid。) okld
启动服务需要什么?
- 创建套接字对
- 获取新的
oklogd
套接字 fork
,setuid/setgid
,exec
服务- 将控制套接字传递给
okd
oklogd
的目的是什么?pubd
的目的是什么?- 为什么我们需要数据库代理?
- 确保每个服务在受损时无法获取其他数据。
- DB 代理协议由应用程序开发人员定义,取决于应用程序的要求。
- 一个可能常见的代理类型是模板化的 SQL 查询。
- 代理强制执行整体查询结构(选择、更新),
- 但允许客户端填写查询参数。
- 20 字节令牌是从哪里来的?
- 作为服务的参数传递。
- 谁检查令牌?
- DB 代理有令牌列表(和允许的查询?)。
- 谁生成令牌?
- 不清楚;系统管理员手动?
- 令牌泄露会怎样?
- 受损组件可能会发出查询。
- 表 1:为什么所有服务和
okld
都在同一个 chroot 中?
- 这是一个问题吗?
- 我们如何决定?
- 那里有哪些可读写文件?
- 可读性:包含服务代码的共享库。
- 可写:每个服务都可以写入自己的
/cores/
。 - 配置文件在哪里?
/etc/okws_config
,由okld
保存在内存中。 oklogd
和pubd
有单独的 chroots,因为它们具有重要状态:
oklogd
的 chroot 包含日志文件,希望确保它没有被修改。pubd
的 chroot 包含模板,希望避免泄露它们(?)。
- 为什么 OKWS 需要为每个服务单独的 GID?
- 需要执行二进制文件,但文件所有权允许 chmod。
- 解决方案:二进制文件由 root 所有,服务是组所有者,模式 0410。
- 为什么是 0410(用户读取,组执行),而不是 0510(用户读取和执行)?
- 为什么不按用户处理?
- 每个用户是否严格更好?
- 用户 X 服务?
- 对于 okcupid 来说,每个服务的隔离可能是有道理的。
- (即,也许他们需要在用户之间进行大量共享?)
- 每个用户隔离需要为每个用户分配 UID,使
okld
变得复杂。
- 并降低性能(尽管对于某些用例可能仍然可以接受)。
OKWS 是否实现了其目标?
- OKWS 解决了典型 Web 攻击列表中的哪些攻击,以及如何解决?
- 除了 XSS 之外的大多数问题都已解决。
- 通过使用专门的模板例程,XSS 在某种程度上得到解决。
- 每个组件被损坏的影响是什么,以及“攻击面”是什么?
okld
:对 Web 服务器机器的根访问权限,但也许没有对数据库的访问权限。
- 攻击面:很小(除了 svc 退出之外没有用户输入)。
okd
:拦截/修改所有用户 HTTP 请求/响应,窃取密码。
- 攻击面:解析 HTTP 请求的第一行;控制请求。
pubd
:损坏模板,利用可能利用某些服务中的错误?
- 攻击面:从 okd 获取模板的请求。
oklogd
:损坏/忽略/删除/伪造日志条目。
- 攻击面:来自 okd、okld、svcs 的日志消息。
service
:向用户发送垃圾,访问 svc 的数据(模块化 dbproxy)。
- 攻击面:来自用户的 HTTP 请求(+来自 okd 的控制消息)。
dbproxy
:访问/更改其所连接的数据库中的所有用户数据。
- 攻击面:来自授权服务的请求。
- 未经授权服务的请求(易于丢弃)。
- 一旦单个服务被损坏,操作系统内核就成为攻击面的一部分。
- Linux 内核漏洞很少见,但每年仍然会出现几次。
- OKWS 假设开发人员在设计层面做正确的事情(也许在实现层面不是):
- 将 Web 应用程序拆分为单独的服务(而不是全部放在一个服务中)。
- 为 DB 代理定义精确的协议(否则任何服务都可以获取任何数据)。
- 性能?
- 似乎比大多数替代方案更好。
- 在负载下性能更好(因此在一定程度上抵抗 DoS 攻击)
- OKWS 与 Apache 相比如何?
- 总体而言,更好的设计。
okld
以 root 身份运行,与 Apache 中没有任何东西相比,但可能不重要。- 两者都没有很好的解决客户端漏洞(XSS 等)
- 对手如何试图破坏类似 OKWS 系统?
- 利用 C++代码中的缓冲区溢出或其他漏洞。
- 在某个
dbproxy
中找到 SQL 注入攻击。 - 在服务代码中找到逻辑错误。
- 发现跨站脚本漏洞。
OKWS 有多成功?
- 论文中描述的问题仍然相当普遍。
- okcupid.com 仍在运行 OKWS,但似乎没有被其他网站使用。
- C++可能不是编写 Web 应用程序的好选择。
- 对于许多 Web 应用程序,获得 C++性能可能并不关键。
- 设计应该适用于其他语言(Python 等)。
- 实际上,6.858 实验室中的
zookws
受 OKWS 启发,运行 Python 代码。
- 对于典型的 Web 应用程序,DB 代理的想法并没有起飞。
- 但是 DB 代理对于限制服务可以访问的数据至关重要。
- 为什么?
- 需要开发人员定义这些 API:额外的工作,会妨碍。
- 很难提前精确定义允许的 DB 查询。
- (尽管如果很困难,可能是安全策略模糊的标志。)
- Apache 的特权分离工作(尽管仍然难以使用)。
- Unix 使非根用户难以操作用户 ID。
- 性能是一个问题(为每个请求运行一个单独的进程)。
scripts.mit.edu
有类似的设计,以不同的 UID 运行脚本。
- 主要担心将用户相互隔离。
- 偏执的 Web 应用程序开发人员可以为每个组件创建单独的锁。
- 敏感系统在更粗粒度上进行分区。
- 信用卡处理公司将信用卡数据与其他所有数据分开。
- 使用虚拟机或物理机器隔离来分割应用程序、数据库等。
你如何将现代 Web 应用程序框架与 OKWS 集成?
- 需要帮助 okd 找出如何将请求路由到服务。
- 需要实现 DB 代理,或其变体,以保护数据。
- 取决于应用代码对静态分析的适应性。
- 或者需要要求程序员为服务注释可以运行的查询。
- 需要确保应用代码可以在单独的进程中运行(可能没问题)。
参考资料
能力和其他保护机制
注意: 这些讲座笔记是从 2014 年 6.858 课程网站 上发布的笔记稍作修改而来。
混淆的副手问题
"混淆的副手"的作者遇到了什么问题?
- 他们的系统有一个 Fortran 编译器,
/sysx/fort
(Unix 文件名语法) - 他们希望 Fortran 编译器记录使用统计信息,但在哪里?
- 创建了一个特殊的统计文件,
/sysx/stat
。 - 给了
/sysx/fort
“家庭文件许可证”(类似于关于/sysx 的 setuid)
- 出了什么问题?
- 用户可以调用编译器,要求将输出写入
/sysx/stat
。
- 例如
/sysx/fort
/my/code.f -o/sysx/stat
- 编译器打开提供的路径名,并成功,因为它的许可证。
- 用户本身不能写入那个
/sysx/stat
文件。
- 为什么
/sysx/fort
只是编译器中的一个错误?
- 原则上,可以通过在各个地方添加检查来解决这个问题。
- 问题:需要在几乎所有打开文件的地方添加检查。
- 完全正确的代码一旦成为 setuid 二进制文件的一部分就会变得有 bug。
- 那么什么是“混淆的副手”?
- 编译器代表两个主体运行:
- 用户主体(用于打开用户的文件)
- 编译器主体(用于打开编译器的文件)
- 不清楚在任何给定时间应该使用主体权限。
我们能在 Unix 中解决这个混淆的副手问题吗?
- 假设 gcc 想要在
/etc/gcc.stats
中保留统计信息 - 可以有一个特殊的 setuid 程序,只能写入该文件
- 不太方便:不能像打开其他文件那样简单地打开文件。
- 如果我们让 gcc 成为某个非根用户(统计文件所有者)的 setuid,会怎样?
- 难以访问用户的原始文件。
- 如果 gcc 是 setuid-root?(坏主意,但让我们弄清楚为什么…)
- 大量潜在的缓冲区溢出可能导致 root 访问权限。
- 需要在 gcc 可能打开文件的每个地方进行检测。
- 当 gcc 打开文件时,我们应该执行什么检查?
- 如果是“内部”文件(例如
/etc/gcc.stats
),也许不需要检查。 - 如果是用户提供的文件,需要确保用户可以访问它。
- 可以查看相关文件的权限。
- 还需要检查导致该文件的目录的权限。
- 潜在问题:竞争条件。
- 如果文件在我们检查和使用之间发生更改会怎么样?
- 常见的漏洞:攻击者用符号链接替换合法文件
- 符号链接可能指向,比如
/etc/gcc.stats
,或/etc/passwd
,或… - 被称为“检查时间到使用时间”的错误(TOCTTOU)。
对这个问题有几种可能的思考方式:
- 环境权限: 进程自动使用的权限是问题所在。任何权限都不应该自动使用。对象的名称也应该是访问它的权限。
- 复杂的权限检查: 特权应用程序难以复制。通过简化的检查,特权应用程序可能能够正确检查另一个用户是否应该访问某个对象。
什么是环境权限的例子?
- Unix 用户 ID,组 ID。
- 防火墙(IP 地址与访问权限)
- HTTP cookies(例如,访问 http://gmail.com 这样的 URL)
通过能力给对象命名有什么帮助?
- 传递文件描述符而不是传递文件名。
- 除非调用者被授权打开该文件,否则无法传递有效的 FD。
我们能否使用文件描述符解决通过 setuid gcc 设置的问题?
- 类似:可以使编译器仅通过 FD 传递接受文件。
- 或者,可以创建一个 setuid 辅助程序,打开
/etc/gcc.stats
文件,将一个打开的文件描述符传递回我们的编译器进程。 - 然后,可以继续像处理任何其他文件一样使用这个打开的文件。
- 如何确保只有 gcc 可以运行这个辅助程序?
- 使 gcc 设置为某个特殊组的 setgid。
- 使辅助程序仅对该特殊组可执行。
- 确保该组没有其他授予的特权。
Capsicum 作者试图通过能力解决什么问题?
- 在各种应用程序中降低不可信代码的特权。
- 总体计划:
- 将应用程序分解为较小的组件。
- 减少最容易受攻击的组件的特权。
- 仔细设计接口,以便一个组件无法危害另一个组件。
- 为什么这么困难?
- 在传统的 Unix 系统中难以降低代码的特权(“沙盒”)。
- 难以为沙盒化代码提供有限的访问权限(对文件、网络等)。
什么样的应用程序可能会使用沙盒化?
OKWS
- 处理网络输入的程序:
- 将输入处理代码放入沙盒中。
- 复杂操作数据的程序:(gzip,Chromium,媒体编解码器,浏览器插件,…)
- 将复杂(且可能有错误)的部分放入沙盒中。
- 从互联网下载的任意程序怎么样?
- 稍微不同的问题:需要隔离未修改的应用程序代码。
- 一个选择:程序员编写他们的应用程序以在沙盒中运行。
- 在某些情况下有效:Javascript,Java,Native Client,…
- 需要在沙盒代码上制定一个环境标准。
- 另一个选择:对现有代码施加新的安全策略。
- 可能需要保留程序员正在使用的所有 API。
- 需要对现有 API 施加检查,在那种情况下。
- 不清楚访问文件、网络等的策略应该是什么。
- 希望避免被欺骗误用特权的应用程序?
- 假设两个 Unix 用户,Alice 和 Bob,正在某个项目上工作。
- 两者都在某个组
G
中,并且项目dir
允许该组访问。 - 假设 Alice 从项目目录向某人发送一个文件。
- 风险:Bob 可能用符号链接替换文件为 Alice 的私人文件。
- Alice 的进程将隐式使用 Alice 的环境特权来打开。
- 可以将这看作对单个文件操作进行沙盒化。
有哪些沙盒化计划(机制)存在(优势,限制)?
- 操作系统通常提供某种安全机制(“原语”)。
- 例如,在 Unix 中的用户/组 ID,正如我们在上一堂课中看到的。
- 今天,我们将研究操作系统级别的安全原语/机制。
- 当您关心保护操作系统管理的资源时通常是一个很好的选择。
- 例如,文件,进程,粗粒度内存,网络接口等。
- 许多操作系统级别的沙箱机制在进程级别工作。
- 适用于可以作为一个单元进行隔离的整个进程。
- 可能需要重新设计应用程序以创建用于隔离的进程。
- 其他技术可以提供更细粒度的隔离(例如,在 proc 中的线程)。
- 语言级别的隔离(例如,Javascript)。
- 二进制仪器化(例如,Native Client)。
- 为什么我们需要这些其他的沙箱技术?
- 更容易控制对非操作系统/更细粒度对象的访问。
- 或者也许可以以与操作系统无关的方式进行沙箱化。操作系统级别的隔离通常与更细粒度的隔离结合使用。
- 更细粒度的隔离通常很难做到正确(Javascript,NaCl)。例如,Native Client 同时使用了细粒度沙箱和操作系统级别的沙箱。
- 将在后续讲座中更详细地讨论这些问题。
计划 0:虚拟化所有内容(例如,VMs)。
- 在虚拟化环境中运行不可信代码。
- 许多示例:x86 qemu,FreeBSD jails,Linux LXC,…
- 几乎是一种不同类别的机制:严格隔离。
- 优势:VM 内部的沙箱代码几乎与外部没有交互。
- 优势:可以沙箱未经修改的代码,不期望被隔离。
- 优势:一些 VM 可以由任意用户启动(例如,qemu)。
- 优势:通常与其他隔离技术可组合,提供额外层次。
- 缺点:难以允许一些共享:没有共享进程,管道,文件。
- 缺点:虚拟化所有内容通常会使 VM 相对较重。
- 每个沙箱都会带来非常重要的 CPU/内存开销。
计划 1:自主访问控制(DAC)。
- 每个对象都有一组权限(访问控制列表)。
- 例如,Unix 文件,Windows 对象。
- “自主”意味着应用程序在对象上设置权限(例如,
chmod
)。
- 每个程序都以某些主体的权限运行。
- 例如,Unix 用户/组 ID,Windows SIDs。
- 当程序访问对象时,检查程序的权限以决定。
“环境特权”:每次访问都隐式使用的权限。
Name Process privileges | | V V Object -> Permissions -> Allow?
- 如何在 DAC 系统上(例如,Unix)沙箱化程序?
- 必须分配一个新的主体(用户 ID):
- 否则,现有主体的权限将被隐式使用!
- 防止进程读取/写入其他文件:
- 在整个文件系统上更改权限?繁琐,不切实际,需要 root 权限。
- 即使如此,新程序也可以创建重要的可全球写入文件。
- 替代方案:
chroot
(同样,必须是 root)。
- 允许进程读/写某个文件:
- 如果可能的话,适当设置文件的权限。
- 将文件链接/移动到沙箱的
chroot
目录中?
- 防止进程访问网络:
- Unix 中没有真正的答案。
- 可能配置防火墙?但不是真正针对进程的。
- 允许进程访问特定的网络连接:
- 如上所述,在 Unix 中没有很好的计划。
- 控制沙盒可以杀死 / 调试 / 等的进程:
- 可以在相同的 UID 下运行,但可能特权太多。
- 该 UID 也可能具有其他特权…
- **问题:**在大多数 DAC 系统上,只有 root 可以创建新的主体。
- 例如,Unix,Windows。
- **问题:**一些对象可能没有明确可配置的访问控制列表。
- Unix:进程,网络,…
- **问题:**文件上的权限可能与沙盒所需的策略不匹配。
- 可以通过使用
chroot
对文件进行某种程度的解决,但很麻烦。
- **相关问题:**使用子特权执行某些操作。
- 回想一下 Alice 通过电子邮件将文件发送到共享组目录的示例。
- “混淆副手问题”:程序是多个主体的“副手”。
- *一个解决方案:*检查组权限是否允许访问(手动,容易出错)。
- *替代方案:*明确为每个操作指定特权。
- 权限可以帮助:能力(例如,fd)结合了对象 + 特权。
- 一些 Unix 功能与纯能力设计不兼容(按名称创建符号链接)。
计划 2:强制访问控制(MAC)。
- 在 DAC 中,安全策略由应用程序自身设置(chmod 等)。
- MAC 试图帮助用户/管理员为应用程序指定策略。
- *“强制”*意味着应用程序无法更改此策略。
- 传统的 MAC 系统试图强制执行军事机密级别。
*示例:*确保绝密程序无法泄露机密信息。
Name Operation + caller process | | V V Object --------> Allow? ^ | Policy -----------+
- *注意:*许多系统在其中具有 DAC + MAC 的方面。
- 例如,Unix 用户 ID 是“DAC”,但可以争论防火墙是“MAC”。
- 并不重要–了解设计空间中的极端点是很好的。
- Windows 强制完整性控制(MIC)/ FreeBSD 中的 LOMAC。
- 为每个进程跟踪“完整性级别”。
- 文件与其关联的最低完整性级别。
- 进程无法写入高于其完整性级别的文件。
- Windows Vista 中的 Internet Explorer 以低完整性运行,无法覆盖系统文件。
- FreeBSD LOMAC 还跟踪进程读取的数据。
- (类似于许多基于信息流的系统。)
- 当进程读取低完整性数据时,它也变得低完整性。
- 传递性,防止对手间接篡改文件。
- 对于沙盒化不是立即有用:只有固定数量的级别。
- SElinux
- *想法:*系统管理员指定系统范围的安全策略。
- 策略文件指定是否应允许或拒绝每个操作。
- 为了帮助决定是否允许/拒绝,文件标记为“类型”。
- (另一个整数值,与 inode 中的 uid、gid 等一起存储。)
- Mac OS X 沙盒(“Seatbelt”)和 Linux
seccomp_filter
。
- 应用程序为是否允许/拒绝每个系统调用指定策略。
- (在 MacOSX 的机制中用 LISP 编写,或者在 Linux 中用 BPF 编写。)
- 根据参数确定系统调用的安全影响可能很困难。
- 路径名指的是什么?符号链接,硬链接,竞争条件,…
- (尽管 MacOSX 的沙盒提供了更多信息)
- 优势: 任何用户都可以对任意代码片段进行沙盒化!
- 限制: 程序员必须分别编写策略和应用代码。
- 限制:有些操作只能以粗粒度进行过滤。
- 例如,在 MacOSX 的过滤语言中的 POSIX
shm
,根据 Capsicum 论文。
- 限制:策略语言可能使用起来很尴尬,无状态等。
- 例如,如果应用程序应该与某个服务器建立精确的一个连接?
- 注意:
seccomp_filter
与常规/旧版seccomp
有很大不同,而 Capsicum 论文讨论的是常规/旧版seccomp
。
- 将策略与应用代码分离是否是个好主意?
- 取决于总体目标。
- 如果用户/管理员想查看或更改策略,可能会很有用。
- 如果应用程序开发人员需要同时维护代码和策略,这将成为问题。
- 对应用程序开发人员来说,可能有助于澄清策略。
- 较少集中的“MAC”系统(Seatbelt、
seccomp
)提供了一种折衷方案。
- 待办事项: 还要看看《赛里斯墙安全策略》
计划 3:能力(Capsicum)。
- 不同的访问控制计划:能力。
- 如果进程有某个对象的句柄(“能力”),就可以访问它。
能力 --> 对象
- 没有特权、访问控制列表、策略等的单独问题。
- 例如:Unix 上的文件描述符是文件的能力。
- 程序无法制造未经合法获取的文件描述符。
- 为什么不? 操作系统创建和管理文件描述符。应用程序无法伪造文件描述符。它必须通过漏洞写入操作系统内存。
- 一旦文件打开,就可以访问它;检查发生在打开时。
- 可以将打开的文件传递给其他进程。
- 文件描述符也有助于解决“检查时间与使用时间”(TOCTTOU)漏洞。
- 能力通常是短暂的:不是磁盘上的 inode 的一部分。
- 启动程序的任何内容都需要每次重新创建能力。
- 全局命名空间
- 为什么这些人如此着迷于消除全局命名空间?
- 全局命名空间需要一些访问控制策略(例如,环境权限)。
- 难以控制沙盒对全局命名空间中对象的访问。
- 内核更改
- 只是为了再次确认:为什么我们需要内核更改?
- 我们能否将所有内容都实现在一个库中(并通过 LD_PRELOAD 加载)?
- 需要操作系统在进入能力模式后拒绝应用程序访问全局命名空间
- 将更多内容表示为文件描述符:进程(pdfork)。
- 一般来说是个好主意。
- 能力模式: 一旦进程进入 cap 模式,就无法离开(包括所有子进程)。
- 在能力模式下,只能使用文件描述符 – 没有全局命名空间。
- 不能通过完整路径名打开文件:不需要像 OKWS 中的
chroot
。 - 仍然可以通过相对路径名打开文件,给定目录的 fd(
openat
)。
- 不能在路径名或符号链接中使用“…”:为什么?
- 原则上,“…” 可能没问题,只要“…” 不走得太远。
- 难以正确执行。
- 假设设计:
- 禁止在根能力中查找“…”。
- 路径名中的非“…”组件不得比“…”多,忽略“.”。
- 假设一个进程对
/foo
拥有能力C1
。 - 在单个进程中的竞争条件,有 2 个线程:
竞争条件示例:
T1: mkdir(C1, "a/b/c") T1: C2 = openat(C1, "a") T1: C3 = openat(C2, "b/c/../..") # should return a cap for /foo/a Let openat() run until it's about to look up the first ".." T2: renameat(C1, "a/b/c", C1, "d") T1: Look up the first "..", which goes to "/foo" Look up the second "..", which goes to "/"
- …
- Unix 权限仍然适用吗?
- 是的 – 仅因为你对目录有一个 cap,就不能访问目录中的所有文件。
- 但意图是沙盒不应依赖 Unix 权限。
- 对于文件描述符,添加一个存储允许操作的包装对象。
- 内核在哪里检查能力?
- 内核中的一个函数查找 fd 号码 – 修改它以检查能力。
- 还修改了查找路径名的
namei
函数。 - 良好实践: 寻找窄接口,否则容易忽略检查。
- libcapsicum
- 应用程序开发人员为什么需要这个库?
- 最大的功能:在沙盒中启动新进程。
- fd 列表
- 主要是将大量文件描述符传递给子进程的便捷方式。
- 通过字符串命名文件描述符,而不是硬编码的 fd 号码。
cap_enter()
vslch_start()
- 使用
exec
而不是cap_enter
进行沙盒化的优势是什么? - 内存中的残留数据:例如 OpenSSL/OpenSSH 中的私钥。
- 应用程序忘记关闭的残留文件描述符。
- 论文中的图 7:
tcpdump
在stdin
、stdout
、stderr
上具有特权。 - 论文中的图 10:
dhclient
具有原始套接字,syslogd
管道,租约文件。
- 优点:任何进程都可以创建一个新的沙盒。
- (即使沙盒也可以创建沙盒。)
- 优点:对资源访问的细粒度控制(如果它们映射到 FD)。
- 文件、网络套接字、进程。
- 缺点: 对持久文件访问跟踪的故事较弱。
- 缺点: 禁止全局命名空间,需要以不同方式编写代码。
替代性的能力设计:纯能力为基础的操作系统(KeyKOS 等)。
- 内核只提供消息传递服务。
- 消息传递通道(非常类似文件描述符)是能力。
- 每个应用程序都必须以能力样式编写。
- Capsicum 声称更加务实:一些应用程序无需更改。
Linux 能力:解决不同的问题。
- 尝试将根的特权划分为更细粒度的特权。
- 由各种能力表示:
CAP_KILL, CAP_SETUID
,CAP_SYS_CHROOT
, … - 进程可以以特定能力运行,而不是以 root 的所有特权。
- 参考:capabilities(7)
在应用程序中使用 Capsicum
- 计划:确保沙盒化进程不使用路径名或其他全局 NS。
- 对于可能需要访问的每个目录,提前打开 FD。
- 要打开文件,请使用从这些目录 FD 开始的
openat()
。
- … 打开大量文件的程序可能会很麻烦。
tcpdump
- 2 行版本:在打开所有 FD 后只需
cap_enter()
。 - 使用
procstat
查看生成的能力。 - 8 行版本:还限制
stdin
/stdout
/stderr
。 - 为什么?避免读取
stderr
日志,更改终端设置,…
dhclient
- 已经进行了特权分离,使用 Capsicum 来加强沙盒(2 行)。
gzip
- 分叉/执行沙盒化的子进程,通过管道使用 RPC 向其提供数据。
- 非平凡的更改,主要是为了为 RPC 编组/解组数据:409 行代码。
- *有趣的错误:*一开始忘记传播压缩级别。
Chromium
- 在其他平台上已经进行了特权分离(但在 FreeBSD 上没有)。
- ~100 行代码用于为沙盒化进程包装文件描述符。
OKWS
- 家庭作业问题有哪些不同的答案?
Capsicum 是否实现了其目标?
- 使用起来有多难/容易?
- 在应用程序中使用 Capsicum 几乎总是需要应用程序更改。
- (许多应用程序倾向于通过路径名打开文件等。)
- 一个例外:Unix 管道应用程序(过滤器)只操作 FD。
- 对通过 FD 处理数据的流式应用程序更容易。
- 其他隔离需要类似的更改(例如,
dhclient
,Chromium)。 - 对于现有应用程序,延迟初始化似乎是一个问题。
- 没有通用解决方案——要么更改代码,要么早期初始化。
- 建议的计划:沙盒化并查看哪些地方出问题。
- 可能会有微妙之处:
gzip
压缩级别错误。
- 它提供了哪些安全保证?
- 提供给应用程序开发人员的保证:沙盒只能在打开的 FD 上操作。
- 结果取决于应用程序开发人员如何划分应用程序、FD。
- 用户/管理员无法从 Capsicum 获得任何直接保证。
- 保证假设 FreeBSD 内核没有错误(大量代码),并且 Capsicum 开发人员捕获了所有通过 FD 而非资源访问的方式。
- 性能开销是多少?(CPU,内存)
- 访问文件描述符的轻微开销。
- 使用
fork
/exec
设置沙盒需要花费O(1msec)
,非平凡的。 - 特权分离可能需要 RPC / 消息传递,可能会引起注意。
- 采用情况?
- 在 FreeBSD 的内核中,现在默认启用(从 FreeBSD 10 开始)。
- 少数应用程序已经修改为使用 Capsicum。
dhclient
,tcpdump
,自论文撰写以来还有几个。参考 - Casper 守护程序帮助应用程序执行非能力操作。例如,DNS 查找,查找
/etc/passwd
中的条目等。参考 - Capsicum 已经移植到 Linux(但不在上游内核存储库中)。
有哪些应用程序不适合 Capsicum?
- 需要控制对非内核管理对象的访问的应用程序。
- 例如:X 服务器状态,DBus,在 Web 浏览器中的 HTTP 来源等。
- 例如:需要确保 DB 文件格式正确的数据库服务器。
- Capsicum 将管道视为用户级服务器(例如,X 服务器)的一个能力。
- 需要从沙盒连接到特定的 TCP/UDP 地址/端口的应用程序。
- Capsicum 通过仅允许对现有打开的 FD 进行操作来工作。
- 需要其他机制来控制可以打开哪些 FD。
- 可能的解决方案:辅助程序可以在能力模式之外运行,根据策略为沙盒化程序打开 TCP/UDP 套接字。
参考
- 苹果沙盒指南
- seccomp_filter
- 强制完整性控制
- 赛里斯防火墙安全政策