我认为这个话题长期以来一直让 iOS 开发社区变得疯狂。我读过太多关于此的文章和帖子,以至于我都数不清了。
所以,我也在处理这个问题,根据 @naqi 的回答,我开始朝这个方向前进,我可能已经找到了一个可行的解决方案。
假设:
当应用程序由于任何原因而被暂停时,似乎会发生此问题(例如,应用程序长时间处于后台并且由于内存压力,操作系统将其发送为暂停状态,或者应用程序处于后台并且用户升级到商店的新版本或自动应用程序更新可以做到这一点)。我不再完全确定暂停意味着什么,但我强烈怀疑应用程序可能会恢复/唤醒,而不会实际显示在屏幕上(由于 bg 任务,但不一定)。
苹果开发者论坛上的一位苹果员工勇敢地回复说“尝试在addDidFinishLaunchingWithOptions
and appDidBecomeActive
“。除了这里的疯狂之外,阅读该评论让我想到也许当应用程序恢复时它会触发addDidFinishLaunchingWithOptions
但当然不是appDidBecomeActive
(因为它可能不会由用户恢复,而是从操作系统在后台处理的任何类型的事件中恢复,我们可能没有控制似乎,或任何其他功能,如 bg 任务或静默推送通知等)。
额外信息:
根据我在网上找到的一篇相当古老的渗透测试文章(https://resources.infosecinstitute.com/iphone-penetration-testing-3/ https://resources.infosecinstitute.com/iphone-penetration-testing-3/)查询钥匙串实际上会将查询寻址到另一个名为securityd
在设备上运行,它神奇地安排查询并将其执行到钥匙串数据库,最后将内容返回到请求应用程序,假设在钥匙串数据库上完成查询时应用程序仍然存在。这让我认为,如果这仍然是正确的,这样的过程可能会陷入某种“DDoS”攻击,您的应用程序(或者可能是所有正在执行的应用程序?不清楚它实际上是如何工作的)执行太多查询。这可能会导致误报,例如 secItemNotFound 或类似错误。再次强调,由于没有人证实这一点,因此将其作为我个人的考虑。
Approach:
从@Naqi 的回答中,我可以排除第 2,3 点和第 4 点,将第 1 点保留为唯一仍然有效的理由。话虽如此,我决定将任何处理钥匙串的 CRUD 操作从addDidFinishLaunchingWithOptions
to appDidBecomeActive
,通过处理其中的应用程序设置指令(无论您的应用程序需要什么),以确保挂起/恢复操作的最终后台事件根本不会影响钥匙串,因为appDidBecomeActive
除非用户实际使应用程序打开并显示在屏幕上,否则不会被调用。当然,这应该只在应用程序启动时发生,因此您可以在中使用布尔标志或类似的信号量方法appDidBecomeActive
以确保您的设置逻辑仅执行一次。
结合上面的方法,在App Delegate中我还显式地实现了application(shouldSaveApplicationState:)
通过返回false
and application(shouldRestoreApplicationState:
仍在返回false
(尽管我认为默认情况下应该已经这样了)。这可能不一定有用,但也值得尝试。
总而言之,在一些随机无法访问钥匙串的受影响设备上,几周以来似乎不再发生这种情况,并且考虑到这种情况在某些设备上几乎每 2/3 天就会发生一次,我认为这可能至少会减弱该问题。
我可以说,受监控的设备都具有不同的配置,是否安装了大量应用程序,存储内存几乎已满或未满,大量应用程序处于背景状态或根本没有,任何外形规格和不同的 iOS 版本。未启用钥匙串备份到云,并且钥匙串上的项目属性至少为kSecAttrAccessibleWhenUnlockedThisDeviceOnly
开放点未完全验证:按说对钥匙串的访问应该是线程安全的,但我发现网络上的不同线程相互矛盾。也许这会以某种方式影响你的逻辑并导致意外的状态
(如果您成功阅读到这里,恭喜您:) )
希望这有助于进一步了解 iOS 中的钥匙串悲剧是怎么回事