Lockbox
Lockbox 是一个 Objective-C 工具类,用于在密钥链中安全地存储数据。使用它来安全地存储小而敏感的数据块。
正在寻找 Swift 版本?请查看 Strongbox。
概述
有些数据,应用程序有时需要存储,而这些数据是敏感的
- 用户名
- 密码
- 应用内购买解锁功能位
- 以及其他任何如果落入错误之手就会变得很糟糕的东西。
要认识到的是,存储在 NSUserDefaults
中的数据是明文存储的!就这一点而言,存储在您应用程序沙箱中的大多数内容也是明文存储的。
令人惊讶的是,无论是新开发者还是有经验的开发者,往往直到为时已晚才意识到这一点。
Lockbox 类的方法使您能够轻松地将任何符合 NSSecureCoding
的基于 Foundation 的对象存储到密钥链中,并从中检索,您无需直接处理密钥链 API!
为了提高安全性,并避免您的应用程序存储的数据与其他应用程序(包括您或其他开发人员的应用程序)存储的数据之间发生冲突,您在类方法中提供用于存储和检索数据的键前缀应为您应用程序的程序包ID。类方法提供了一些便利,简化了对Lockbox的使用。但是,如果您需要能够在您的应用程序和iOS8扩展等之间访问一组常见的键,则可能需要重写键前缀。为此,您可以实例化自己的Lockbox实例,并传入自定义的键前缀,然后调用类上的相同方法(作为实例方法)。(类方法和实例方法在签名上是相同的。实际上,类方法是在一个类静态的Lockbox实例上操作的。)
需要注意的是,钥匙串并不是为了存储大量数据而设计的,因此不要仅仅因为您想存储数据就试图使用这些API存储大量数据。在这种情况下,请考虑替代的加密技术。
方法
Lockbox 3包含以下方法,此处展示为类方法。您也可以在您的Lockbox实例上调用相同的方法(作为实例方法)。
通用对象存储和检索
+archiveObject:forKey
+archiveObject:forKey:accessibility
+unarchiveObject:forKey
这些方法使用NSKeyedArchiver
和NSKeyedUnarchiver
分别来编解码您的对象。您的对象必须遵守NSSecureCoding
。
+archiveObject:forKey:...
方法返回一个表示钥匙串操作是否成功的BOOL
值。方法+unarchiveObjectForKey:
在成功时返回非nil
值,在失败时返回nil
。返回值是类型为id
的,但您将其分配为任何已知的数据类型。例如
NSDate *today = [NSDate date];
[Lockbox archiveObject:today forKey:@"theDate"];
...
NSDate *theDate = [Lockbox unarchiveObjectForKey:@"theDate"];
以下是对accessibility
参数的说明。
以下是对从Lockbox v2.x API迁移到Lockbox v3 API的信息。
Lockbox 2.x及更低版本包括以下已弃用方法,此处展示为类方法。您可以在您的Lockbox实例上调用相同的方法(作为实例方法)。
+setString:forKey
+setString:forKey:accessibility
+stringForKey
+setArray:forKey
+setArray:forKey:accessibility
+arrayForKey
+setSet:forKey
+setSet:forKey:accessibility
+setForKey
+setDictionary:forKey
+setDictionary:forKey:accessibility
+dictionaryForKey
+setDateForKey
+setDateForKey:accessibility
+dateForKey
所有 setXxx
方法返回 BOOL
提示密钥链操作是否成功或失败。当 xxxForKey
方法成功时返回非 nil
的值,失败时返回 nil
。
《setXxx》方法将覆盖键串中已存在的键值的值,或者如果该键值对不存在,则向键串中添加该键值对。
在所有方法中,您可以使用简单的键名,如"MyKey",但请注意,Lockbox会在键名前添加您的应用程序包ID(如果您正在使用类方法,则为您自己的键;如果您正在使用Lockbox实例)。因此,实际用于存储和检索数据的键看起来更像是"com.mycompany.myapp.MyKey"或"my.custom.key.MyKey"。这确保了您的应用程序,只有您的应用程序,可以访问您的数据。
具有accessibility
参数的方法需要一个键串项可访问性常量。您可以使用此常量来控制您的键串项何时可读。例如,传入kSecAttrAccessibleWhenUnlockedThisDeviceOnly
将仅在设备解锁时使该项可访问,并且不会将此项迁移到新的设备或安装。没有特定accessibility
参数的方法将使用kSecAttrAccessibleWhenUnlocked
,这是iOS最新版本中的默认设置。
迁移到Lockbox v3 API
没有自动从旧setXxx
方法迁移到新归档/反归档方法。事实上,这是几乎不可能的,因为没有方法可以知道您为任何给定键存储了什么,以便能够正确检索数据。v3 API与v2.x API不兼容。
需要进行手动迁移。您需要使用现在已弃用的类型特定的v2.x方法来获取您的数据,然后再使用新的archiveObjectForKey:
方法再次存储数据。
您可以在启动时进行一次迁移,仅适用于所有使用旧方法存储的Lockbox数据。然后通过Lockbox或User Defaults或其他地方存储另一个键来记录此迁移已完成。因此,在随后的启动中,您不需要再次进行迁移。事实上,这将是冗余的,并且可能会损坏您的数据。
ARC支持
从v2.0开始,Lockbox仅支持ARC。对于非ARC支持,请使用v1.4.9。
需求与限制
要使用此类,您需要将Security
框架添加到您的项目中。
您的项目必须启用密钥链共享才能使Lockbox访问密钥链,但您可以删除Xcode添加的任何密钥链组。据称,权限对于任何密钥链访问都是必需的,而不仅仅是共享。
此类是为了在Cocoa Touch和iOS下使用而编写的。代码和测试在Mac OS下的iOS模拟器中运行正常。但是在Cocoa和Mac OS下使用该类存在一些问题。两个平台之间存在一些密钥链API的差异。
在设备上运行单元测试的注意事项
如果在设备上运行应用程序的单元测试时,在Lockbox方法中遇到SecItemCopyMatching错误(错误码为34018),您可以通过对单元测试.xctest文件夹进行代码签名来避免这些错误。
将Run Script阶段添加到您的单元测试目标的构建阶段中
codesign --verify --force --sign "$CODE_SIGN_IDENTITY" "$CODESIGNING_FOLDER_PATH"
文档
链接到最新的CocoaDocs: cocoadocs.org/docsets/Lockbox/
许可
有关详细信息,请参阅LICENSE文件。