本系列文章讨论 iOS 在技术层面如何保证用户数据的安全。苹果 2019 年更新了安全设计公开文档,广泛涉及系统安全,加解密,App,网络,付款,Apple ID 等各方面。本文目的不是对它进行翻译,而是提取主要信息并以个人理解希望简明易懂地介绍 iOS 操作系统的安全设计。如果需要更详细的信息,可以阅读原文。了解基本的密码学概念 (例如 AES, RSA, Diffie-Hellman 等) 会对理解本文有很大帮助。
移动设备相比台式机或服务器更容易被窃取/丢失,更容易受到物理级别的攻击。所以数据安全有以下几个主要设计目标:
iOS 设备的硬件提供了几个重要的功能来帮助实现这些目标。
加解密: 每个 iOS 设备上都有一个专用的 AES-256 加解密硬件集成在闪存和系统内存的 DMA 通道上。无需软件进行加解密运算,提高效率。
UID: 每个设备独特的 AES-256 key。A9 之后,这个 key 是在生产过程中完全在 Secure Enclave 内部独立生成。软件,固件和 JTAG 等调试接口都没有权限读取,外界只能看到由这个 key 加密或解密之后的内容。那 UID 有什么用?UID 是文件系统加密 key 的一部分,又仅存在于 Secure Enclave 里,所以闪存芯片只能在本机访问。
随机数生成: CPU 使用系统启动和中断事件的时间变化作为随机来源。Secure Enclave 使用基于多个 ring oscillator + CTR_DRBG 的硬件随机数生成器生成它的 key。
Effaceable Storage: 除了能安全生成 key 之外,需要的时候还要能不可恢复地清除。闪存的均衡磨损 (wear-leveling) 技术可能会导致保存的 key 存在于闪存中多个位置。苹果设计了 “Effaceable Storage”,能直接读写闪存的特定物理位置,确保 key 能被安全清除。 需要的时候还要能不可恢复的清除
首先 iOS 的所有用户数据文件都是加密存储的。每个文件创建时会生成一个 per-file key,在文件写入闪存时通过硬件用 AES-XTS 加密。per-file key 会进一步被 class key 加密并保存在文件的 metadata 中。class key 用于对文件不同级别的保护,每一个级别对应一个 class key(比如最高级别的 class key 只有在设备解锁状态下才可用)。获取了一个 class key,就可以解密对应级别所有文件的 per-file key,然后用 per-file key 解密这些文件。
所有加密之后的 key,又会进一步被 file system key 加密。file system key 在 iOS 安装时或每次设备数据被清除时生成。file system key 的目的不是保护数据的机密性,而是用于实现快速清除数据。在执行数据清除时,会删除 file system key,使设备上所有文件永久无法解密,实现了快速安全清除。
iOS 文件系统加密
文件加密体系:
这个设计提供了安全性和灵活性,比如用户修改密码,不需要重新加密所有的文件的 key 甚至文件本身,只需要重新加密几个 class key 即可。
Passcode 是用户设置的解锁密码。它保护 class key,进而保护所有用户文件。由于 passcode 复杂度相对低 (经常是4或6位数字),容易被穷举攻击。那如何抵抗穷举攻击?
设备中我们需要对不同的文件提供不同程度的保护。iOS 上每个文件创建时都会被指定一个级别 (class)。每个级别对应一个 class key。
Complete Protection
class key 由 UID 和 passcode 保护。每次设备锁定 10 秒后,系统将解密后的 class key 从内存中删除。这个级别的文件必须在设备再次解锁后才能访问。
Protected Unless Open
有些文件需要在设备锁定时写入(比如后台下载)。这些文件的 per-file key 被另一个 key 加密 (通过 ECDH over Curve25519 生成)。拥有 private key 的情况下可以解密这个 class 的 per-file key。
Protected Until First User Authentication
和 Complete Protection 基本一致,只不过设备锁定后 class key 不会被删除。相当于每次系统启动后第一次解锁后文件都可以访问,直到下次重启。
No Protection
class key 只被 UID 保护,在清除设备所有数据时才被删除。
iOS 通过这些设计实现了文章开始提到的目标。
iOS Keychain 也实现了类似的分级保护机制。但增加了 kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
。这个级别的 class key 在每次 passcode 修改之后都会被清除,并且数据不会被备份。1Password 使用这个级别存储 Touch ID/Face ID 解锁 app 所需要的 key。具体设计细节就不介绍了,可阅读原文。