Lec 22 Fork一致性
阅读资料: SUNDR (2004)
我们日常信任的一些存储服务:Github、Gmail、AFS、Dropbox等等,这些产品的公司比如Google或许会用心良苦,但是,不可避免地:
- 服务或软件或硬件存在漏洞,可能会被利用
- 攻击者可能猜测出服务器管理员的账密并修改软件
- 云提供商的员工可能存在腐败或者操作疏漏
关键问题:我们是否能从不可信的服务中获得可信的存储? 这是个难题!而且这些问题是真实存在的。
- 攻击者会破坏源码存储库,甚至可能篡改源码
- 2003年出现过Debian服务器被攻破的时间
- 2011年SourceFroge(全球最大的开源软件仓库)遭到攻击
- 2019年Canonical(Ubuntu公司)被黑客攻破
这篇论文SUNDR包含了一些不错的思想。
- 类似的思想出现在Git和区块链中
- Keybase(已经被Zoom收购)直接收到SUNDR的影响
总览
- SUNDR的目标
SUNDR的目标
首先保密性不是SUNDR的目标,它只使用了加密技术来验证数据的正确性。
What: 我们需要完整性(integrity)
- reader可以看到正确的数据
- 服务器不能欺骗他们接受不正确的数据
- 服务器无法遗漏合法的更新
- 例如,不能遗漏一个关键的合法补丁
- (这证明是个难题!)
How: 我们有哪些工具确保完整性
- 加密哈希
- 数字签名
内存寻址存储
加密哈希
SHA-1
- h = hash(data), h很小,但是data可以很大,对于SHA-1来说,h是160位
- 安全性 = 不可能找到两个不同的输入具有相同的哈希值
- 用于命名数组或者验证完整性
使用加密哈希的安全存储
使用一个普通的(不可信的)K / V 服务器,假设
客户写入
v:k = hash(v)
put(k, v)
客户段读取
k:v = get(k)
check hash(v) == k
这是不可信服务器上的安全存储,如果服务器损坏了数据,客户端检查会失败。这种方法称为内存寻址存储(content-addressed storage)或者 内容哈希存储(content-hash storage)。基于这样的事实,我们不能随意选择 K,必须是通过hash(v)而来。reader客户端获得键的方式——可以把键嵌入在URL中,或者将键发布在一个安全的网页上,甚至直接通过电子邮件发送给需要访问数据的用户。
我们可以基于内容哈希存储构建类似列表或类似树形结构,【key, 目录块,文件块】,直到根key就可以访问地访问整个结构,即使块存储在不可信的服务器上。
不足
内存寻址存储不足以支持读/写文件系统。 因为键的值不能更改,k=hash(v),这种存储时不可变的
数字签名
数字签名(Digital signatures)允许可变存储。首先公钥/私钥对,只有所有者知道私钥,sig = sign(data, k_priv),ok = verify(data, sig, k_pub),我们可以使用任何K/V方案,只要reader知道写入者的k_pub。
客户端写入(或更新)
(k, v): 客户端调用put(k, v + sign(v, k_priv))客户端读取
k:客户端调用v + sig = get(k);verify(v, sig, k_pub)
现在所有者可以修改,任何知道公钥的人都可以获取并检查返回的V。可以确定k_priv的所有者曾经签署过该值(这不完全等同于v 是 k 的正确值)
数字签名shufu
SUNDR的
服务器可以签署伪造的日志条目吗?
不行,他需要知道授权用户的私钥
FQA
问:SUNDR提供验证文件是否被篡改的手段。但是,它是否可以将文件内容对恶意服务器隐藏或加密?
答:不可以。SUNDR仅提供数据完整性保证,而不提供机密性。用户可以自行加密文件内容以保护机密性。
问:在一个相当大的文件系统中计算i-handle的速度如何?
答:计算SHA-1的速度相当快(每字节约10个时钟周期)。此外,如果只更改一个区块,只需要对该区块重新计算哈希,然后对所有区块哈希以得到根哈希。签名步骤是耗时的部分。SHA计算的开销不可忽视,因此文中提出通过允许i-handle存储哈希值和i-table变更的简短日志,来避免多次操作中重复计算哈希树。这也加快了已检查过最近版本的客户端的校验速度——它们只需应用日志中的几次操作。
问:什么是分叉一致性和获取-修改一致性?
答:分叉是一种攻击,在这种攻击中,恶意服务器向不同用户展示不同的文件系统内容。在SUNDR中,这种攻击是可能的。例如,用户X更新了文件F,而用户Y稍后读取F,但服务器向Y展示的是F的旧内容(即X更新之前的内容),这就是分叉攻击。
分叉一致性意味着,如果服务器对用户X隐藏了任何操作,则它不能向X和Y展示彼此后续的操作。服务器一旦隐瞒了一个操作,必须呈现两个不同版本的文件系统,一个仅反映X的操作,另一个仅反映Y的操作。
获取-修改一致性是服务器在正确运行时的表现:每个用户都能看到每个其他用户的操作结果。
问:论文中所说的用户可以通过通信检测到分叉是什么意思?
答:作者所说的通信是指用户之间的任何带外通信(如电子邮件、聊天等)。例如,如果用户A告诉用户B请查看文件“x”,而B未看到“x”,则说明服务器对文件系统进行了分叉(或A在对B撒谎)。除了带外通信外,作者还建议使用时间戳箱。在比特币中,还有另一种方法来解决分叉问题,我们将在下周讨论。
问:SUNDR目前有哪些产品或内部系统应用?
答:据我所知,没有直接的应用。但这些想法在其他去中心化系统中得到了应用,例如git、账本等。唯一直接受SUNDR影响的商业系统是Keybase(后被Zoom收购)。
问:在什么情况下会选择将数据存储在不受信的服务器上?
答:你不会选择将数据存储在已知已受损的服务器上,但可能会使用一个原本认为可靠但后被攻破的服务器。攻击者可能会更改服务器上的文件,之后恢复这种攻击造成的损害很困难。如果此服务器存储着广泛依赖的内容(如Debian Linux的源码),问题就十分严重。类似的攻击曾发生过:Canonical在2019年被攻破。
问:为什么分叉一致性是好的?分叉不都是不理想的吗?
答:确实,分叉并不是理想状态。但在普通假设下,似乎无法防止恶意服务器向客户分叉内容,即对一些客户端隐藏一些更新。所以我们必须接受分叉的可能性。
SUNDR的做法是限制服务器在隐藏和展示操作时的自由度。具体来说,SUNDR限制服务器只能分叉,不能合并。这意味着,服务器可以在某一时刻之前向Y展示X的所有更新,并在此之后向Y隐藏X的所有更新,但服务器不能只隐藏X的某个更新而展示之后的更新。服务器一旦对两个客户端分叉,就不能在不暴露分叉的情况下让两个客户端看到彼此的后续更新。
更重要的是,分叉的后果很可能很明显(合作用户不再看到彼此的更新),这样一来用户就会很快意识到自己被分叉了,从而停止信任存储服务,并转向其他更可靠的服务。
问:如果客户端检测到分叉攻击,应该怎么做?
答:对此没有特别好的答案。你肯定会想要换一个存储服务提供商,并需要检查各个分叉并合并(或慎重地丢弃)任何冲突的写入。这意味着具体的应用和文件格式都需进行具体处理;没有通用的技术。更令人担忧的是,你必须考虑分叉(以及用户更新被隐藏)可能对外界产生的坏影响——即用户可能基于分叉的(不正确)数据作出的任何决策。
问:论文中说“分叉一致性是在没有在线可信方的情况下实现的最强的完整性概念”。为什么?
答:如果假设客户端通常处于离线状态且不能直接通信,这似乎是合理的。若只有一个客户端同时在线,或者客户端只能与SUNDR服务器通信,客户端似乎没有什么办法检测服务器是否在隐藏其他客户端的最新更新。
但如果客户端始终在线,并可以通过互联网直接通信,情况可能不同。客户端可以直接交换消息,相互提醒对方最新的更新、数据的哈希、日志条目,甚至文件数据。这似乎可以消除SUNDR服务器执行分叉攻击的可能性。但在这样的设计中,互联网或客户端本身可能充当在线可信方,这会使最初的声明在技术上正确。而恶意的互联网(或时间同步服务)也可能执行分叉攻击。
本文的一个主要观点是,获得分叉一致性后,通过一些外部手段可以相对轻松地实现接近线性化的行为。这正是3.2节的主题。
论文阅读: SUNDR
思考题
在简单的设想方案中,fetch和 modify操作都被记录在日志中并进行签名。假设一种替代设计,其中只有modify操作被签名并记录在日志中。这样设计是否允许恶意服务器破坏 fetch-modify consistency(获取-修改一致性)或 fork consistency(分叉一致性)?为什么或为什么不?
摘要
SUNDR 是一种网络文件系统,设计用于在不受信任的服务器上安全存储数据。SUNDR 允许客户端检测恶意服务器操作员或用户对文件的任何未授权修改尝试。SUNDR 协议实现了一种称为“分叉一致性”的特性,该特性保证只要客户端能够看到彼此的文件修改,就能检测到任何完整性或一致性方面的故障。描述的实现性能与 NFS 相当(有时更好,有时稍逊),但提供了显著更强的安全性
1. 引言
SUNDR 是一种网络文件系统,旨在解决数据完整性和可访问性之间的长期矛盾。保护数据通常被视为在存储服务器周围建立更高“围栏”的问题——限制访问人数、禁用可能会被远程利用的不必要软件,并保持最新的安全补丁。然而,这种方法有两个缺点。首先,经验表明,人们常常没有建立足够高的围栏(或者有时将围栏交由不完全可信的管理员负责)。其次,更重要的是,高围栏会带来不便;它们限制了人们访问、更新和管理数据的方式。
这一矛盾在自由软件源代码库中尤为明显。自由软件项目通常涉及地理分散的开发人员从互联网各地提交源代码更改,使得用防火墙来阻止攻击者的方案不切实际。更糟糕的是,许多项目依赖第三方托管服务。通过攻陷 SourceForge,攻击者可以在可能运行于成千上万甚至数百万台机器的软件中植入微妙的漏洞。并且攻击事件并不仅限于学术探讨。
我们并不指望服务器绝对安全,而是开发了 SUNDR 这一网络文件系统,以减少对存储服务器的信任需求。SUNDR 使用加密方法保护所有文件系统内容,使客户端可以检测任何对文件的未授权更改。与以前的拜占庭容错文件系统 [6, 27] 通过分布信任但假定一部分服务器诚实不同,SUNDR 将文件写权限完全赋予用户的公钥。即便是获得完全管理权限的恶意用户,也无法让客户端接受他无写权限的文件内容修改。
凭借其安全特性,SUNDR 还为数据管理提供了新的选择。使用 SUNDR,组织可以将存储管理外包而不必担心服务器操作员篡改数据。SUNDR 还提供了新的数据备份和恢复选项:在发生灾难后,SUNDR 服务器可以从不受信任的客户端文件缓存中恢复文件系统数据。由于客户端始终加密验证文件系统的状态,它们不在意数据是从不受信任的客户端恢复的,还是始终保存在不受信任的服务器上。
本文详细介绍了 SUNDR 文件系统的设计和实现。我们首先描述了 SUNDR 的安全协议,接着介绍了一个原型实现,该实现的性能在软件开发工作负载和微基准测试下通常与流行的 NFS 文件系统相当。我们的结果表明,像 CVS 这样的应用程序可以在享受 SUNDR 强大安全保障的同时,承受较低的性能损耗。
2. 设置
SUNDR 提供了一个远程存储的文件系统接口,类似于 NFS [29] 和其他网络文件系统。例如,为了保护源代码库,项目成员可以将远程 SUNDR 文件系统挂载到目录 /sundr,并使用 /sundr/cvsroot 作为 CVS 仓库。所有的检出和提交操作都通过 SUNDR 进行,从而确保用户能够检测到托管站点对仓库内容的任何篡改企图。
图 1 展示了 SUNDR 的基本架构。当应用程序访问文件系统时,客户端软件会在内部将它们的系统调用转换为一系列获取和修改操作,其中获取指的是检索文件内容或验证本地缓存的副本,修改指的是使新的文件系统状态对其他用户可见。获取和修改操作分别通过 SUNDR 协议的 RPC 调用实现。协议在第 3 节中说明,服务器设计在第 5 节中描述。

要设置 SUNDR 服务器,需要在一台联网的机器上运行服务器软件,并使用专用的 SUNDR 磁盘或分区。服务器可以托管一个或多个文件系统。创建文件系统时,需要生成一个公钥/私钥超级用户签名密钥对,将公钥提供给服务器,并保密保存私钥。私钥提供对文件系统根目录的独占写权限,同时直接或间接地允许访问根目录下的所有文件。然而,这些权限仅限于单个文件系统。因此,当一个 SUNDR 服务器托管多个由不同超级用户管理的文件系统时,没有任何单一人员可以拥有所有文件的写访问权限。
SUNDR 文件系统的每个用户(user)也拥有一个签名密钥。建立账户(account)时,用户与超级用户(superuser)交换公钥。超级用户通过根目录下的两个由其拥有的文件来管理账户:
- .sundr.users 列出用户的公钥和数值 ID,
- 每个用户都有一个唯一的公钥,用来证明其身份,以及一个数值 ID,作为用户在系统中的标识
- sundr.group 指定组及其成员
- 这个文件定义了不同的用户组及其成员关系。它指明了哪些用户属于哪些组,以便于权限管理
要挂载文件系统,必须将超级用户的公钥作为客户端的命令行参数,还必须让客户端能够访问私钥。(SUNDR 也可以使用更灵活的证书方案来管理密钥和组;系统只需要一种方法来验证用户彼此的密钥和组成员身份。)
在本文中,我们使用“用户”一词来表示拥有映射到 .sundr.users 文件中某个用户 ID 的签名密钥的实体。根据上下文,这可能是持有私钥的个人,或者是代表用户操作的客户端。然而,SUNDR 假设用户知道自己上次执行的操作。在实现中,客户端会记住它代表每个用户执行的最后操作。要在不同客户端之间切换,用户需要同时携带其私钥和其最后一次操作的记录(以版本号简明表示)。另外,用户还可以为不同客户端分配多个用户 ID(可能使用相同的公钥),并将所有文件权限赋予一个个人组。
SUNDR 的架构在服务器管理和文件系统管理之间划分了明确的界限。管理服务器无需任何超级用户私钥。为了最佳的安全性,密钥对应在单独的、受信任的机器上生成,且私钥不应保留在服务器上,即使是内存中也不应有。重要的密钥,如超级用户密钥,应在不使用时离线存储(例如存储在软盘上并用密码短语加密)。
3. SUNDR协议
SUNDR协议允许客户端检测未经授权的文件修改尝试,即便攻击者完全控制了服务器。当服务器行为正确时,获取操作完全反映了此前所发生的授权修改。我们称这一特性为“获取-修改一致性(fetch-modify consistency)”。如果服务器不诚实,客户端则强制执行一种稍微弱一些的特性,称为“分叉一致性(fork consistency)”。直观地说,在分叉一致性下,一个不诚实的服务器可能导致用户A的获取操作错过用户B的修改。但是,任何一方用户在看到对方的后续操作时都能检测到攻击。因此,为了维持欺骗,服务器必须分叉两个用户的文件系统视图。换句话说,如果A的客户端接受了B的某次修改,那么至少在B进行该次修改之前,两个用户都拥有一致的、获取-修改一致的文件系统视图。
我们已经正式定义了分叉一致性【16】,并在假设数字签名和抗碰撞哈希函数的基础上,证明了SUNDR协议能够实现分叉一致性【17】。因此,违反分叉一致性可能意味着底层加密技术被破坏,或实现偏离了协议,或者我们将高级Unix系统调用映射到底层获取和修改操作的方式存在缺陷。
为了讨论分叉一致性的含义并描述SUNDR系统,我们从一个简单的虚拟文件系统开始,该系统通过极大的低效性实现分叉一致性(第3.1节)。然后我们提出一个改进的系统——带有更合理带宽需求的“序列化SUNDR”(第3.3节)。最后我们放宽了序列化要求,得到“并发SUNDR”,即我们构建的系统(第3.4节)。
3.1 简单的虚拟文件系统
在SUNDR的粗略近似版本中,虚拟文件系统避免任何并发操作,允许系统消耗不合理的带宽和计算资源。服务器在文件系统上维护一个单一的、不可信的全局锁。要获取或修改文件,用户首先获得该锁,然后执行所需操作,再释放锁。只要服务器诚实,操作是完全有序的,每个操作在下一个操作开始之前完成。
虚拟文件服务器存储了每个曾执行过的获取或修改操作的完整、有序列表。每个操作还包含执行该操作的用户的数字签名。签名不仅涵盖了该操作,还包括了所有先前操作的完整历史。例如,在完成五个操作后,历史可能如下所示:为了获取或修改文件,客户端首先获取全局锁,下载整个文件系统的历史,并验证每个用户最近的签名。客户端还检查其自身用户的前一个操作是否在下载的历史中(除非这是用户第一次在文件系统上进行操作)。
接着,客户端遍历操作历史,以构建文件系统的本地副本。对于每次遇到的修改操作,客户端还进一步检查该操作是否确实被允许,使用用户和群组文件来验证签名用户是否与文件的所有者或群组匹配。如果所有检查均成功,客户端将新操作附加到列表中,签署新的历史,将其发送至服务器,并释放锁。如果操作是修改操作,附加的记录包含了一个或多个文件或目录的新内容。
现在非正式地考虑一下恶意服务器可能做的事情。为了让客户端相信文件已被修改,服务器必须向其发送签名的历史。假设服务器不知道用户的密钥,无法伪造签名,那么客户端接受的任何修改都必须是经过授权的用户签名的。然而,服务器仍可以通过隐藏其他用户的先前操作来诱使用户签署不适当的历史。例如,考虑上述历史的最后一次操作,如果服务器未向用户B展示对文件f2的最近修改,会发生什么情况。用户A和B将分别签署以下历史记录: