间歇性和临时性iOS钥匙串故障

时间:2018-08-13 21:30:24

标签: ios swift keychain callkit pushkit

我们有一个应用程序在很大程度上依赖于能够使用iOS的 Tree tree = new Tree(Frame, SWT.BORDER); tree.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { TreeItem item = tree.getItem(Display.getCurrent().getCursorLocation()); if(item != null) { ... 访问用户的会话令牌。当我们的应用打开时,首先要检查的是令牌是否可用-否则,我们向用户显示登录屏幕。为此,我们不使用任何第三方库,而直接将Keychain的{​​{1}} / Keychain与以下选项一起使用:

  • SecItemAdd()
  • SecItemCopyMatching()

在正常使用过程中,我们几乎没有这个问题。

问题

我们有用户报告说,他们实际上登录时,打开应用程序时会看到登录屏幕(建议kSecClassGenericPassword找不到值)。我们发现,我们发现在杀死并重新启动该应用后,用户恢复了正常(会话在kSecAttrAccessibleAlwaysThisDeviceOnly中找到)。一旦发现此问题,我们尝试添加指数退避以继续查询钥匙串,并认为它可能仅在开始的几秒钟内不可用。这行不通,并向我们证明了整个应用启动过程中都无法使用钥匙串。我们无法重现此问题。它似乎间歇性地发生。

在进一步调查中,我们发现用户通常在出现此问题之前已经收到 VoIP推送。我们仍然无法可靠地重现此问题,但是在调试后,发现我们的Keychain被发现为Keychain,当收到这些推送时(我们也依赖它),这是之前用户将打开他们的应用程序以查看其被伪“注销”。

我们使用PushKitPKPushRegistry来进行VoIP Push。这要求我们的应用启用“背景模式:IP语音”。我们按照Apple文档的建议使用所有这些信息。这是一个示例:

Keychain.session

此代码取决于nil在收到VoIP推送后立即可用。如前所述,我们已经看到了不可用的实例,因此该函数注销并仅返回。

我还发现了this relevant Apple forum post,暗示这可能是iOS的错误。

有人可以帮助我们解决这个问题吗?任何帮助将不胜感激。即使实际上这是一个iOS错误,我们也可以采用其他解决方法。

2 个答案:

答案 0 :(得分:2)

我认为这个话题长期以来一直在使iOS开发者社区疯狂。我读了太多关于此的文章和主题,以至于我失去了计数。

所以,我也正在处理此问题,根据@naqi的答案,我开始朝这个方向发展,我可能已经找到了可行的解决方案。

假设

该问题似乎是由于某种原因而被挂起的(例如,长时间处于后台运行的应用程序以及由于操作系统将其发送到挂起状态而导致的内存压力,或者应用程序处于背景和用户状态从商店升级到新版本或自动应用更新完成)。我不再完全确定暂停状态意味着什么,但我强烈怀疑该应用程序可能会恢复/唤醒而没有真正出现在屏幕上(由于bg任务,但不一定)。 Apple开发人员论坛上的一名Apple资深会员勇敢地回答说“尝试在addDidFinishLaunchingWithOptionsappDidBecomeActive之间设置延迟”之类的内容。除了这里的疯狂之外,阅读该评论使我考虑到,也许当应用恢复运行时,它会触发addDidFinishLaunchingWithOptions,但是触发appDidBecomeActive(因为它可能不会被用户恢复,而是从任何用户那里恢复)操作系统在后台处理的某种事件,我们似乎无法控制它,或者其他任何功能,例如bg任务或无声推送通知等。

其他信息

根据我在网络上找到的很老的渗透测试文章(https://resources.infosecinstitute.com/iphone-penetration-testing-3/),查询钥匙串实际上可以将查询处理到设备上运行的另一个名为securityd的进程,该进程神奇地调度了查询,然后将其执行到钥匙串数据库,最后将内容返回给请求的应用程序,前提是当在钥匙串数据库上完成查询时,该应用程序仍然处于活动状态。这使我认为,如果这仍然是正确的,那么这种过程可能会以“ DDoS”攻击的形式落入其中,您的应用程序(或可能正在执行的所有应用程序?尚不清楚其实际工作方式)在其中执行了太多查询。这可能导致错误的肯定错误,例如secItemNotFound或类似错误。再次,由于没有人确认这一点,因此请保留我的个人意愿。

方法

从@Naqi答案中,我可以排除点2,3和4,将点1保留为唯一仍然有效的理由。话虽如此,我决定通过处理其中的应用设置说明(无论您的应用需要什么)将所有处理钥匙串的CRUD操作从addDidFinishLaunchingWithOptions移至appDidBecomeActive。挂起/恢复操作的最终背景事件根本不会影响钥匙串,因为除非用户实际使应用程序打开并显示在屏幕上,否则appDidBecomeActive不会被调用。当然,这只会在应用启动时发生,因此您可以在appDidBecomeActive中使用bool标志或类似的信号量方法来确保设置逻辑仅执行一次。

结合上述方法,在应用程序委托中,我还通过返回application(shouldSaveApplicationState:)false仍返回application(shouldRestoreApplicationState:来显式实现false(即使我默认情况下应该已经是这样)。这可能不一定有用,但值得尝试。

总结一下,自从几周以来,在某些随机无法通过钥匙串访问的受影响设备上,现在似乎不再发生了,考虑到这种情况发生的时间大约是每2/3天,也就是说,我认为这可能削弱了至少。

我可以说,受监视的设备均处于不同的配置中,是否安装了许多应用程序,存储内存是否已满,或者有很多应用程序处于bg或根本没有存储,任何形式和不同iOS版本。未启用将钥匙串备份到云的功能,并且钥匙串上的项属性至少为kSecAttrAccessibleWhenUnlockedThisDeviceOnly

未完全验证开放点:假设对钥匙串的访问应该是线程安全的,但是我发现Web上的其他线程相互矛盾。也许这可能会以某种方式影响您的逻辑并导致意外状态

恭喜您,如果您在这里阅读完了:)

希望这有助于进一步了解iOS中此钥匙串悲剧的发生情况

答案 1 :(得分:1)

我遇到了类似的问题,在与WWDC的工程师交谈后,我们发现导致这一现象的原因很少。

  1. 我们经常打电话给Keychain,这可能会导致价格昂贵并且某些通话无法完成或超时的情况

  2. 如果应用程序不提供钥匙串访问组或未将其添加到带有钥匙串的保存交易中,则Xcode会生成一个,但它是动态的并且可以在开发环境之间更改

  3. 如果您在应用生命周期的后期提供了访问组,那么您的旧钥匙串值将仍然与该应用相关联,并且将使用现在提供的访问组来创建新值
  4. 这还意味着,当您查询钥匙串时,您必须提供访问组,否则您将获得对最早找到的内容的引用。

编辑:格式化