Restic设计原理( 四 )


锁(Locks)restic 存储库设计方式是允许并发访问,甚至并行写入 。但是,有些功能工作效率要求更高,甚至需要对存储库进行独占访问 。为了实现这些功能,需要restic进程在执行任何操作之前,在存储库上创建一个锁 。
锁有两种类型:排他锁和非排他锁 。一个进程最多可以在存储库上拥有一个独占锁,并且在此期间不得有任何其他锁(独占和非独占) 。对于排它锁,可能并行存在多个 。
锁是子目录locks中的文件,其文件名是内容的存储ID 。它的加密和鉴权方式与存储库中的其他文件相同,并包含以下 JSON 结构:
{"time": "2015-06-27T12:18:51.759239612+02:00","exclusive": false,"hostname": "kasimir","username": "fd0","pid": 13607,"uid": 1000,"gid": 100}字段 exclusive 定义了锁的类型 。当要创建新锁时,restic 会检查存储库中的所有锁 。找到锁时,会测试锁是否超时,默认时间为大于30分钟以上 。如果锁是在同一台机器上创建的,即使对于没有达到超时时间的锁,它也会通过向它发送信号来测试进程是否还活着 。如果失败,restic 假定进程已死,并认为锁是无用的 。
当要创建一个新锁并且没有检测到与其他冲突锁时,restic 创建一个新锁,等待并检查存储库中是否出现其他锁 。根据其他锁的类型和要创建的锁,restic 要么继续,要么失败 。
备份和重复数据删除为了创建备份,restic 会扫描源目录中的所有文件、子目录和其他条目 。来自每个文件的数据被拆分为可变长度的 Blob,这些 Blob 以 64 字节的滑动窗口定义的偏移量进行切割 。该实现使用 Rabin 指纹来实现内容定义分块 (Content Defined Chunking, CDC) 。初始化存储库时,随机选择一个不可约多项式(不可约多项式,顾名思义即不能写成两个次数较低的多项式之乘积的多项式)并保存在文件 config 中,增加安全性,让水印攻击更加困难 。
小于 512 KiB 的文件不会被拆分,Blob 的大小为 512 KiB 到 8 MiB 。实现的目标是Blob平均 1 MiB 大小 。
对于修改过的文件,只有修改过的 Blob 必须保存在后续备份中 。即使在文件中的任意位置插入或删除字节,仍然可以继续工作 。
威胁模型restic 的设计目标是能够将备份安全地存储在不完全受信任的位置,例如共享系统,其他人可以在其中访问文件(在系统管理员的情况下)甚至修改或删除它们 。
一般假设:

  • 创建备份的主机系统是受信任的 。这是最基本的要求,对于创建可靠的备份至关重要 。
  • 用户使用的是正版restic
  • 用户不与攻击者共享存储库密码 。
  • restic 备份程序并非是设计防止攻击者删除存储位置的文件 。对此无能为力 。如果需要保证这一点,一定要选择没有第三方可以访问的安全位置
  • 如果密钥泄露,整个存储库将重新加密 。使用当前的密钥管理设计,如果不重新加密整个存储库,就不可能安全地撤销泄露的密钥 。
  • 针对 restic 使用的加密原语(即 AES-256-CTR-Poly1305-AES 和 SHA-256),尚无法实现攻击 。如果能够实现,会使 restic 提供的机密性或完整性保护变得无用 。
  • 算力方面进步还无法实现对 restic 加密保护的暴力攻击
restic 备份程序可以保证以下内容:
  • 如果没有存储库的密码,就无法访问存储文件和元数据的未加密内容 。密钥文件中除了用于信息描述目的的元数据之外的所有内容都经过加密和鉴权的 。缓存中的内容也进行了加密,防止metadata泄露
  • 对于存储在存储库中的所有数据的修复(坏 RAM、损坏的硬盘)可以被检测到
  • 被篡改的数据将无法解密
考虑到上述假设和保证,以下是各种的攻击手段:
对备份存储位置具有读取权限的对手可以:
  • 尝试对存储库副本进行暴力密码猜测攻击(推荐使用 30 个以上字符的长密码) 。
  • 通过文件访问模式推断哪些包可能包含树 。
  • 通过使用存储库对象的创建时间戳推断备份的大小 。
具有网络访问权限的对手可以: