存储在 iOS 设备之上的每一个文件皆采取四种数据保护类型之一,这些保护手段将确定文件何时可以接受读取与写入操作。而开发者则能够以授权或者编程方式对这些保护类型加以设置。大家应该尽可能利用此类机制保护用户数据,而依效果由好到差排序,这四种手段分别为:
文件仅能够在设备解锁时进行访问。当设备被锁定时,你的应用将收到一条 UIApplicationProtectedDataWillBecomeUnavailable 通知,并在 10 秒钟之后失去对受保护文件的访问能力。尽可能多地选用这种方式,但对于那些需要在后台持续运行的应用,请不要选择这一机制。
当设备被锁定时,各文件仍然能够进行创建,而已经打开的文件则可继续接受访问。利用这一机制,我们可以在后台完成各类相关任务——例如保存新数据或者更新数据库。
当设备引导完成后,对应文件可在用户输入密码后随时接受访问——即使是在设备被锁定的情况下。利用这种方式,您可以随时读取运行在后台的文件。
NSFileProtectionNone
文件始终可接受访问。系统在某些情况下需要利用这一机制,但其并不适合于绝大多数第三方应用。
如果大家希望对受保护的文件进行访问,则操作会返回
(代码 257) 或者
- NSFileReadNoPermissionError
(代码 513) 错误。
- NSFileWriteNoPermissionError
感兴趣的朋友可以参阅苹果 iOS 安全白皮书以了解与上述保护类型相关的更多技术信息。
需要强调的是,数据保护机制并不适用于模拟器。Mac 设备上采用的 FileVault 加密机制亦使用完全不同的工作原理。即使设置了保护类型,其在随后的读取中也无法起效。你将始终读取
——至少在我的 Mac 上是如此。因此请务必在直机之上进行数据保护能力测试。
- NSURLFileProtectionCompleteUntilFirstUserAuthentication
要完成这项设置,大家无需进行任何操作——因为自 iOS 7 以来,所有 iOS 版本都将其作为默认设置。
你的应用或者扩展容器所创建的文件具体使用怎样的默认保护等级,取决于
权限,其在 Xcode 中显示为“Data Protection(数据保护)”。
- com.apple.developer.default-data-protection
你需要为相关应用及其全部扩展设置这一选项。在这方面,请注意以下两点:
1. 根据 Quinn“The Eskimo!”在 苹果开发者论坛 上所言,此权限需要在应用安装之前进行设置。
你权限设置(通过配置文件存放在您的 App ID 当中)中的默认数据保护等级仅在应用容器的创建过程中进行使用。
根据我个人的实际调查,如果变更一款已安装应用的权限设置,那么有时候其能够将新等级应用于后续文件,但有时候却不能。不过可以肯定的是,变更不会影响原有文件,因此除非你打算开发一款全新应用,否则最好以编程方式设置保护类型。关于这一点,我们将在后文中详加说明。
2. 由于此权限仅应用于您的应用或者扩展容器,因此大家需要以编程方式为共享容器设置保护等级。
牢记以上注意事项,权限设置就变得非常容易。在佻的 Xcode 项目设置当中,前往应用或者扩展的“Capabilities”标签并启用“Data Protection”即可。就这么方便。
如此一来,你的应用权限文件当中(如果尚不存在,请另行创建)会被添加一条数据保护权限,且该权限的值被设置为 NSFileProtectionComplete。其还将在苹果开发者网站 Certificates, Identifiers & Profiles 中的开发者 App ID 之上启用数据保护功能。
感兴趣的朋友亦可查看苹果应用发布指南当中的“启用数据保护”部分,其中简要说明了如果更新此 Capabilities。
接下来我们要面对的是 NSFileProtectionComplete(具体依以上说明),而后同时对苹果开发者网站 Certificates, Identifiers & Profiles 部分中的权限文件与 App ID 进行保护等级变更。大家必须对这两个值进行手动同步,否则会在构建时出现无效权限错误。
这里具体介绍导航流程:Identifiers > App IDs > (具体应用 ID) > Edit > Data Protection > Sharing and Permissions。您可以在这里从三种保护等级当中选择其一进行设置(但不包括 NSFileProtectionNone)。
该权限文件当中最关键的关注点为 NSFileProtectionCompleteUnlessOpen。我发现即使是进行自动配置时,Xcode 都不会更新网站之上配置文件进行的变更。大家可以删除~/Library/MobileDevice/Provisioning Profiles/ 以强制要求 Xcode 重新下载该配置文件。如果觉得有些麻烦,你也可以选择使用 Craig Hockenberry 提供的 Provisioning QuickLook 插件 以快速判断当前配置是否正确。
你不可将 None 设置为默认等级,因为苹果开发者网站的 Certificates, Identifiers & Profiles 部分并不提供此选项。另外,大家也绝对不应该选择这种自我放弃的作法。
如果你的应用程序已安装在用户设备上,而没有设置权限,并且你想要的其他设备 NSFileProtectionCompleteUntilFirstUserAuthentication,则需要以编程方式设置保护类型,以保护新文件并升级现有的文件。请注意,您不需要设置使用这些 API 的权利。
我们首先来看单独一个文件,其中包含多个 API 以接收作为选项的保护类型。如果你打算写入一个来自 Data/NSData 的新文件,则使用:
- try data.write(to: fileURL, options: .completeFileProtection)
对于现有文件,你可以使用 NSFileManager/FileManager 或 NSURL:
- try FileManager.default.setAttributes([.protectionKey: FileProtectionType.complete], ofItemAtPath: fileURL.path)
- // or
- // cast as NSURL because the fileProtection property of URLResourceValues is read-only
- try (fileURL as NSURL).setResourceValue(URLFileProtection.complete, forKey: .fileProtectionKey)
在 Core Data 情况下,你可以在添加持久存储时传递此保护类型:
- try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: [NSPersistentStoreFileProtectionKey: FileProtectionType.complete])
感兴趣的朋友可以参阅苹果 iOS 应用编程指南当中的“利用磁盘内加密保护数据”章节。
Quinn"The Eskimo!"还在苹果开发者论坛上发布了这条 非常实用的信息:
在默认情况下,数据保护值会在项目创建过程中直接自父目录处继承。举例来说,如果您将目录设置为 NSFileProtectionComplete,则在该目录中创建的任何项目都将默认被设置为 NSFileProtectionComplete。
权限文件负责控制容器内 root 目录下的数据保护值,而此值亦将作用于容器内所创建的任何内容的保护等级。然而,如果您为某一目录明确设置了该值,则该目录内创建的后续条目将默认使用这一新值。
因此,你可以使用 FileManager/NSFileManager 或者 NSURL 作为目录 URL 以替代文件 URL,或者在创建此目录时提供该保护属性:
- try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: [.protectionKey: FileProtectionType.complete])
如此一来,你随后即可按正常方式在该目录中创建文件了。
当为某一目录设置保护等级时,该目录中全部现有文件的保护等级并不会随之变化。因此,大家需要为该目录中的每个文件设置正确的保护等级。
你可以用 FileManager.DirectoryEnumerator/NSDirectoryEnumerator 完成这项工作:
- guard let directoryEnumerator = FileManager.
- default.enumerator(at:
- directoryURL, includingPropertiesForKeys: [], options: [], errorHandler: {
- url,
- error - >Bool in print(error)
- return true
- })
- else { print("Could not create directory enumerator at \(directoryURL.path)")
- return
- }
- // NSEnumerator is not generic in Swift so we have to deal with Any.
- for urlAsAny in directoryEnumerator { do {
- try (urlAsAny as ! NSURL).setResourceValue(URLFileProtection.complete, forKey: .fileProtectionKey)
- } catch { print ( error )
- }
- }
大家可以轻松利用 PSPDFKit Instant 保护你的文件。如果大家设置了一项默认数据保护等级,Instant 将自动使用该保护选项,你无需进行任何其它操作。如果大家希望为存储在 Instant 当中的特定文件及注释设置不同的保护等级,则可在 PSPDFInstantClient 上使用 dataDirectory 类属性以访问 Instant 的数据存储路径,而后使用以上提到的变更方法。感兴趣的朋友可以参阅我们的 Instant 数据保护指南以了解更多细节信息。
https://pspdfkit.com/blog/2017/how-to-use-ios-data-protection/
1.NSFileProtectionComplete:
https://developer.apple.com/documentation/foundation/nsfileprotectioncomplete
2.NSFileProtectionCompleteUnlessOpen:
https://developer.apple.com/documentation/foundation/nsfileprotectioncompleteunlessopen
3.NSFileProtectionCompleteUntilFirstUserAuthentication:
https://developer.apple.com/documentation/foundation/nsfileprotectioncompleteuntilfirstuserauthentication
4.NSFileProtectionNone:
https://developer.apple.com/documentation/foundation/nsfileprotectionnone
5.iOS 安全白皮书:
https://www.apple.com/business/docs/iOS_Security_Guide.pdf
6.Provisioning QuickLook 插件:
https://github.com/chockenberry/Provisioning
7.Instant 数据保护指南:
https://pspdfkit.com/guides/ios/current/instant/data-protection/
移动开发前线
「移动开发前线」是 InfoQ 旗下关注移动开发技术的垂直社群。投稿请发邮件到 editors@cn.infoq.com,注明“移动开发前线投稿”。
时下最火热的技术非 AI 莫属,那么,目前到底都有哪些 AI 落地案例呢?机器学习、深度学习、NLP、图像识别等技术又该如何用来解决业务问题?
AICon2018 全球人工智能技术大会上,我们邀请了来自 360、京东、腾讯、百度、Etsy、微软、饿了么、摩拜、搜狗、携程、微博等国内外知名企业的 AI 应用落地负责人,前来分享他们可供参考的最新 AI 落地案例和技术探索,或许可以给你一些启发,目前大会 8 折报名火热进行中,点击“阅读原文”了解详情!
来源: https://juejin.im/entry/5a02dd52f265da43085d757a