A Distributed Sandbox for Untrusted Computation on Secret Data 阅读笔记
摘要
本文提出了ryoan的设计与原型实现。ryoan提供了一个分布式沙箱,并利用硬件enclave来保护沙箱实例以免受潜在恶意计算平台的攻击。受保护的沙箱实例限制不受信任的数据处理模块,以防止用户数据的泄漏。
- 它提供了一个沙箱来限制单个数据处理模块,防止它们泄漏数据;
- 它使用可信的硬件允许远程用户验证单个沙箱实例的完整性并保护它们的执行
- 沙箱可以配置为允许受限的代码模块以受控的方式进行通信,从而在互不信任的各方之间实现灵活的委托。
在ryoan的模型中,应用程序和服务提供商都是不可信的。它们可能通过隐蔽通道偷走用户的私密数据。Ryoan的目标是防止这种隐蔽通道,并阻止不受信任的应用程序秘密使用用户数据。
Ryoan原型实现使用Native Client(NaCl)作为沙箱,使用Intel SGX作为硬件飞地。每个SGX enclave包含一个NaCl沙箱实例,该实例加载并执行不受信任的模块。NaCl实例相互通信,形成一个分布式沙箱,为所有参与方(用户和不同的服务提供者)提供强大的隐私保障。此外,Ryoan还假定了一个面向请求的数据模型,其中受限制的模块只处理一次输入,并且在接收到输入后不能读写持久存储。
论文的贡献:
- 一种新的执行模型,允许互不信任的各方在不可信的基础设施上以分布式方式处理敏感数据。
- 分布式沙箱原型的设计和实现,它限制不可信的代码模块(可能在不同的机器上),并强制执行防止机密泄露的I/O策略。
威胁模型
- 用户不信任服务提供商
- 服务提供商不信任第三方计算平台
- 服务提供商不信任外包方
- 服务提供商信任自身的代码和计算平台
- 所有人都信任Ryoan和SGX
Ryoan没有采取任何措施来防止不信任的各方有意(或通过漏洞)泄露秘密。此模型适用于服务提供商在其自己的计算平台上部署代码的情况。当在不同的平台提供商上执行时,Ryoan提供了针对恶意操作系统的保护,以及通过加密保护数据。
威胁模型仅考虑了软件接口的隐蔽通道,但是没有考虑由于硬件限制(hardware limitations)或执行时间(execution time)导致的隐蔽通道和侧信道。
Intel Software Guard Extensions (SGX)
SGX允许进程保护部分地址空间不受特权软件的侵犯。具有sgx能力的机器上的进程可以构造一个飞地。Ryoan使用SGX来证明所有的飞地都有相同的初始状态和相同的身份。在将敏感数据传递给Ryoan之前,用户可以向SGX请求证明,确认提供的身份是Ryoan identity。
enclave code可以访问到所有不属于其他飞地的内存空间,但是enclave code并不能利用到x86的所有feature。所有的enclave code都是unprivileged,特权级是ring3. 所有提升特权级的指令都会产生fault。
硬件安全限制
hardware limitations 是ryoan不能够处理的,一些hardware security limitations如下:
-
SGX page faults
特权软件可以操作飞地的页表 -
cache timing
驻留在同一个核心上的两个进程可以使用缓存计时来获取彼此的细粒度信息。 -
Address bus monitoring
尽管SGX对RAM中的数据进行加密,但如果攻击者通过嗅探器或修改过的RAM芯片监视地址总线,它就会形成一个缓存粒度的侧信道或隐蔽通道。如果不进行新的架构更改,Ryoan就无法防止此类攻击。 -
processor monitoring
处理器监控单元(pmu)为片上事件提供广泛的性能计数器信息。如果在enclave-protected执行中发生的事件更新了PMU,那么不可信代码就能够获取到这些信息并构建出秘密数据。
native client
谷歌的Native Client(NaCl)是一个运行在x86平台上使用软件故障隔离(software fault isolation)技术的沙箱。NaCl由一个验证器(verifier)和一个服务运行时(server runtime)组成。为了保证不受信任的模块无法跳出NaCl的SFI沙箱,验证者会对二进制文件进行分解,并验证分解后的指令是否可以安全执行。
NaCl会拦截系统调用,并代替NaCl执行系统调用。
设计
Ryoan是一个分布式沙箱,它执行一个有向无环图(DAG),用于与操作敏感数据的不可信模块进行通信。Ryoan通过将外部可见的行为与秘密数据的内容解耦,防止模块泄漏敏感数据。
Ryoan提供了一个受限的IO模型来防止数据泄漏,表1总结了Ryoan对不可信代码施加的属性,以实现可观察行为与秘密输入数据的安全解耦:
下图1是Ryoan分布式沙箱的一个实例。
为了向后兼容,Ryoan模块支持为libc编写的程序,其中可以包括完全编译的语言和构建在libc之上的运行时。为了减少内存使用,我们的Ryoan原型不支持即时编译器(JIT)。在enclaves中不允许Ring 0执行,因此Ryoan不能直接支持操作系统或hypervisor。一个Ryoan模块可以是一个Linux程序,或者它可以包含一个库操作系统。
SGX为用户生成一个不可伪造的远程认证,证明Ryoan实例正在平台上的飞地中执行。用户可以建立一个加密通道,她知道该通道将在该Ryoan实例中终止。SGX保证这块飞地的密码机密性和完整性不受特权软件的操纵。
主enclave创建所有的Ryoan实例并在它们之间依照用户的指示创建加密通信。一旦分布式拓扑结构建立,主服务器将拓扑中每个节点的验证都会转发给用户,由用户验证配置是否符合预期。然后用户输入机密数据。Ryoan通过在DAG的模块添加标签来保护机密数据。Ryoan的所有实例形成了一个分布式沙箱。
如下图2所示,SGX使用硬件来验证Ryoan沙箱,Ryoan沙箱使用软件来加密验证模块的初始状态。
ryoan原型实现
强制拓扑
用户要么定义受限模块的通信拓扑,要么明确批准它。拓扑是具有单向链接的模块的有向无环图(DAG)。DAG规范首先被传递到一个初始飞地,我们称之为主飞地。它包含Ryoan提供的标准的、受信任的初始化代码。master请求操作系统启动包含规范中列出的模块的ryanan实例的enclaves。这些飞地可以托管在不同的机器上。
主服务器使用SGX执行本地或远程认证,以验证单个Ryoan enclaves的有效性,然后让DAG中的邻居enclaves通过使用不可信网络或本地进程间通信作为传输,通过密钥交换建立加密保护的通信通道。用户可以通过认证来验证主服务器的有效性,并询问它所需要的拓扑是否已经初始化。在此之后,用户使用DAG的入口和出口区域建立安全通道,并开始数据处理。
通信中的标签模型
Ryoan Label
Ryoan采用了以前的基于标签的系统,使多个互不信任的模块能够对敏感数据进行合作。Ryoan使用保密标签来标记机密数据和见过该机密数据的飞地。Ryoan标签可以被认为是在飞地级别粒度上跟踪污染。
文件进行签名,并使用相关的公钥作为这些模块的标记。该公司还可以使用不同的密钥对对其模块二进制文件进行签名,使它们成为不同的主体,从而实现特权分离。
label manipulation rules
每个模块都有能力添加或删除与其主体相对应的单个标记——每个模块都可以解密自己的秘密。当模块读取带有非空标签的数据时(例如,从用户或其他模块的输出中),它将数据标签与当前标签合并,后者将成为模块和数据的新标签。Ryoan用模块的标签标记模块的输出数据。
如上图3所示,Alice使用他自己的标签对数据进行标记,第一个23andMe模块添加了23andMe标签,以确保其秘密在交给亚马逊的机器学习模块后不能流回用户手中。这个控制很重要,因为用户控制着拓扑。第二个23andMe模块将其标签从输出的数据标签中移除。
Ryoan 数据审计跟踪
当数据遍历模块的DAG时,Ryoan跟踪哪些模块处理每一项用户工作。每个工作单元的审计跟踪可以作为DAG输出的一部分提供给用户。虽然Ryoan不能验证模块正在执行它们预期的或声明的功能,但审计跟踪仍然是有用的。
Data oblivious communication[1]
数据处理模块可以通过观察数据流来推断隐私数据,因此数据流必须要独立于输入数据的内容。一旦模块读取了它的输入数据,Ryoan就永远不会移动数据来响应不受信任模块控制的活动。
Ryoan通过固定模块输出的大小、应用程序确定输入的大小来保证数据流模式不会泄露隐私数据:
- 在模块开始处理之前,每个ryoan实例从其他input-connected的ryoan实例读取它的整个输入
- 输出的大小是输入大小的多项式函数
- 当模块输出完成时,它会通知 ryoan,并将模块的输出写入所有与output-connected的 ryoan 实例
Ryoan 将模块输出封装在一个包含元数据的消息中,元数据描述了哪部分数据是模块输出,哪部分是填充(如果有的话)。
Ryoan 确保输出大小是输入的固定函数,所以如果输出不够大,就是模块的错误。Ryoan 将截断输出太大和并对输出太小的进行数据填充。但是,模块作者应该能够描述给定大小的输入请求的最大可能输出。
Module confinement
模块验证
Ryoan模块验证通过对加载的代码强制执行一组约束来确保模块可以安全执行。Ryoan使用NaCl的loadtime代码验证器来确保模块的代码遵循严格的格式。NaCl的代码格式设计为高效验证和高效沙盒,限制控制流目标,并干净地将代码与数据分离。内存访问被限制在模块占用的地址空间内。
模块生命周期
模块声明周期包括:creation、initialization、wait、process、output、destruction/rest。
Ryoan’s confined environment
任何带有限制标签的模块,都要在 ryoan 的限制环境中执行。当一个模块接收到一个请求中包含的秘密数据时,它进入了有限的环境,失去了通过任何系统调用与不受信任的操作系统通信的能力。因此,ryoan 必须提供一个足够的系统 api。
Ryoan对外提供的服务有:
- 虚拟文件系统
- mmap
processing-time channels
受限模块不能通过系统调用与不受信任的操作系统通信,但它可以决定何时完成数据处理,根据数据选择不同的处理时间,从而成为操作系统泄密的通道。解决方法有:
-
固定处理时间
-
量子化处理时间(quantized processing time)
事先预设好一些固定的执行时间,可以减少潜在的处理时间粒度。 -
访问随机性
Ryoan 不允许被限制的模块,从操作系统中获得随机性。获得随机性意味着恶意模块可以从输入中泄漏随机位,例如随机选择一个输入位并利用其处理时间泄漏它。如果用户重复输入数据,那么具有随机性的恶意模块最终会通过其处理时间通道泄漏整个输入,即使每个输入工作单元只泄漏一次。使用固定的处理时间消除这个通道。 -
one shot at input data
Ryoan 被设计成允许每个模块有一个单一的机会来处理它的输入数据,没有机会将状态从一个输入传递到下一个输入。这个一次性政策限制了数据泄露。因此,ryoan 必须阻止模块在重置后再次访问相同的输入:- ryoan的拓扑结构必须是有向无环图
- Ryoan 的重置机制在读取机密数据后,删除所有依赖于状态修改的数据
- 若连接中断,ryoan 会重新初始化所有安全连接,以防输入重放攻击
防止特权程序入侵
ryoan必须要依赖于不安全的操作系统(可能还有hypervisor)提供的服务。ryoan必须对来自不安全组件的结果进行验证,ryoan提供了ryoan-libc库代替libc库,以防止恶意程序入侵。