【问题标题】:iOS KeyChain not retrieving values from backgroundiOS KeyChain 未从后台检索值
【发布时间】:2012-05-19 04:39:49
【问题描述】:

我目前将用户名(电子邮件)以及电子邮件和密码的加盐哈希值存储在 iOS KeyChain 中。我正在使用 here 找到的 ARC'ified 版本。

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
[wrapper setObject:APP_NAME forKey:(__bridge id)kSecAttrService];
[wrapper setObject:email forKey:(__bridge id)kSecAttrAccount];
[wrapper setObject:token forKey:(__bridge id)kSecValueData];

当我需要在应用程序处于活动状态时为我的网络调用提取令牌时,这一切都很好。它适用于从干净的启动登录,以及整个网络调用。当应用程序在后台时,问题就开始了。

请记住,这只是偶尔发生,我还没有将其归结为特定的 iOS 版本或设备。

用户旅行了一个位置(区域监控),我想用他们的状态更新服务器。我尝试将令牌从钥匙串中拉出,就像我对其他所有网络调用所做的那样,并更新状态。但对于一些用户来说,价值为零。没有它,我无法更新网络内容。为什么这对大多数人有效,但对一小部分人无效?

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
NSString *token = [wrapper objectForKey:(__bridge id)kSecValueData];

我已经回到钥匙链包装器的非 ARC 版本,但我仍然得到相同的结果。我将不胜感激对此的任何反馈。这只是我用户的一小部分,但这是我想解决而不是担心的问题。提前致谢。

另外,我所有的后台工作都设置在 backgroundTask 中,以防止事情超时。我对钥匙串周围的工作没有任何问题,但在我的令牌被填满之前我不会让事情继续进行。

编辑 我已经解决了他们的钥匙串没有从后台检索值的问题。我将在下面发布答案并接受它,因为我觉得这个问题以后可能对其他人有价值。

【问题讨论】:

    标签: iphone ios background keychain lockscreen


    【解决方案1】:

    我的问题接近于原因,但不完全是。在阅读了一个又一个博客,一个又一个教程之后,我终于找到了一个暗示可能会发生什么的文章。

    锁定的主屏幕。钥匙串教程总是将钥匙串的可访问性设置留空,因此它默认为 Apple 的最低/最安全的访问级别。但是,如果用户在锁定屏幕上有密码,则此级别不允许访问钥匙串。答对了!这解释了偶发行为以及为什么这只发生在一小部分用户身上。

    一行代码,解决所有问题。

    [wrapper setObject:(__bridge id)kSecAttrAccessibleAlways forKey:(__bridge id)kSecAttrAccessible];
    

    在我设置用户名和密码值的地方添加这一行。奇迹般有效。希望这会帮助那里的人。它让我困惑了很长一段时间,直到我能够将这些碎片拼凑在一起。

    【讨论】:

    • 谢谢!这很有帮助。
    • 我们已经处理这个问题好几个星期了。你是救生员!
    • 请尽可能避免使用…AccessibleAlways,或存储仅提供有限权限的令牌(例如,允许您阅读新提要项目但不能发布的令牌)。通过这样做,您明确放弃了一定程度的加密。如果您的应用可以等到第一次解锁,最好使用…AfterFirstUnlock 并引导您的用户先解锁他们的设备。
    • 这是一个非常糟糕的主意,因为这意味着此凭据数据不再受到保护。虽然需要做更多的工作,但重要的是创建一个派生凭据,而不是仅用于您期望在后台需要的有限访问权限,仅此而已。该受限凭证可能会在一段时间后过期,并且每次打开应用程序时都会创建一个新凭证,从而使旧凭证失效。如果派生凭证被泄露,这可以确保用户的安全。请参阅 WWDC 2013 会议 204 了解此内容。
    • 在这里呼应@JoeyHagedorn - 在 44:24 处收听 WWDC 2013 会议 204“多任务处理的新功能”,在 25:30 处收听 WWDC 2013 会议 709“使用钥匙串保护秘密”。您可以在asciiwwdc.com看到这些谈话的文字内容
    【解决方案2】:

    使用kSecAttrAccessibleAfterFirstUnlock 而不是kSecAttrAccessibleAlways


    来自Apple's documentation

    kSecAttrAccessibleAfterFirstUnlock
    钥匙串项中的数据不能 重启后可以访问,直到设备解锁一次 由用户。

    第一次解锁后,数据仍然可以访问,直到下一次解锁 重新开始。 推荐用于需要访问的项目 后台应用程序。 具有此属性的项目迁移到新的 使用加密备份时的设备。

    【讨论】:

    • 这个答案应该是评论……
    • 这个答案似乎很完美,因为kSecAttrAccessibleAlways 已经被弃用了
    【解决方案3】:

    在我的例子中,watchOS2 在 iOS 端访问钥匙串数据。

    一开始使用的是kSecAttrAccessibleWhenUnlockedThisDeviceOnly。无论 iPhone 是否被锁定,我都可以读取数据。当手表尝试访问钥匙串时,我会收到错误消息,这让我非常困惑: : SecTrustEvaluate [叶子 IssuerCommonName SubjectCommonName]

    在某些情况下它会变成: :SecOSStatusWith 错误:[-25308] 错误域 = NSOSStatusErrorDomain 代码 = -25308 “ks_crypt:e00002e2 未能 'oe' 项目(6 类,包:0)在钥匙串被锁定时尝试访问项目。” UserInfo={NSDescription=ks_crypt: e00002e2 failed to 'oe' item (class 6, bag: 0) 在钥匙串被锁定时尝试访问项目。}

    如果我得到更多信息,我会更新我的答案。

    【讨论】:

      【解决方案4】:

      这可能是由于 Apple 的数据保护政策,从开发人员的角度来看,该政策在某种程度上是模糊的。解决方法是在应用启动时检查钥匙串是否可访问,如果不可访问,您可能会根据您的应用类型终止您的应用(使用适当的弹出窗口)。

      +(BOOL) isKeychainAccessible
      {
          NSString *keychainTestKey = @"keychainTestKey";
          NSString *keychainTestValue = @"keychainTestValue";
          [self createKeychainValue:keychainTestValue forIdentifier:keychainTestKey];
          NSString *loadedValue = [self keychainStringFromMatchingIdentifier:keychainTestKey];
          [self deleteItemFromKeychainWithIdentifier:keychainTestKey];
          return ([keychainTestValue isEqualToString: loadedValue]);
      }
      

      【讨论】:

        猜你喜欢
        • 2015-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-09
        • 1970-01-01
        • 2015-01-05
        • 1970-01-01
        相关资源
        最近更新 更多