【问题标题】:Security implications of storing a password in Settings.bundle and getting with CFPreferencesCopyAppValue在 Settings.bundle 中存储密码并使用 CFPreferencesCopyAppValue 获取的安全隐患
【发布时间】:2009-08-08 11:06:59
【问题描述】:

对于这个问题看似显而易见,但无论出于何种原因,我都无法在 Apple 文档中找到关于 Settings.bundle 密码信息的存储位置和方式的明确答案。我的问题:如果我需要为应用程序存储一些凭据,并且我使用 Settings.bundle 以便使用 IsSecure = YES 将密码输入到 Apple 设置区域中的 PSTextFieldSpecifier 文本字段中,然后我使用我的应用程序访问该值CFPreferencesCopyAppValue,从不将其写入 NSUserDefaults 并且仅通过网络安全地发送,与在我自己的应用程序设置中使用钥匙串存储和检索密码相比,这种存储和检索方法的安全性如何?感谢您的意见。

【问题讨论】:

  • 考虑存储哈希而不是密码。请参阅下面的答案。
  • 感谢您的好建议——正如我在几年前问过这个问题时提到的那样,我只是坚持使用钥匙串。
  • 是的。这是一个不错的选择,自从您第一次提出要求以来,Apple 肯定已经对其进行了改进。

标签: iphone cocoa-touch security sdk settings.bundle


【解决方案1】:

CFPreferencesCopyAppValue 只是 Core Foundation 访问您在使用 NSUserDefaults 时获得的相同信息的方式。在安全性方面,功能完全相同。也就是说,它没有加密。只有在它被遮蔽的意义上,它才是安全的。 “正确”的答案是使用钥匙串。

与之相反的是,许多应用程序使用NSUserDefaults 来存储密码。您可能会争辩说,除非密码控制对任何价值信息的访问,否则尝试使用钥匙串是不值得的。这让我想到了支持在设置应用程序中使用安全字段的第二个论点:钥匙串 API 是可怕的,至少根据我的经验,编写无错误代码是很棘手的。

【讨论】:

  • 很高兴知道,谢谢。我将坚持使用钥匙串——我不清楚设置信息是否与 NSUserDefaults 位于同一位置。
  • 您可能对使用 SFHFKeychainUtils 感兴趣:github.com/ldandersen/scifihifi-iphone/tree/…。我用它来存储密码,它确实简化了钥匙串的使用。
  • 我发现 Apple 示例代码具有 Keychain Services 的钥匙串包装器的实现非常容易遵循(然后使用包装器进行您自己的应用程序钥匙串管理),如果您剥离从视图控制器中取出演示代码,我认为这是该示例最容易引起混淆的地方。
【解决方案2】:

不要将用户密码保存在设置包中。
它不安全。

记住,你不需要知道原始密码是什么,你需要知道用户输入的密码是否匹配原始密码。在 iOS 中处理密码的正确方法是

  • 使用钥匙串,就像其他人提到的那样
  • 使用 SHA-512 或其他加密生成加密单向哈希函数,并将生成的哈希和盐存储在 NSUserDefaults

在这些选项中,加密密码和存储哈希+盐是迄今为止最简单的。存储密码的方法如下:

  1. 从用户那里获取密码
  2. 创建随机盐值
  3. 使用 SHA-512 和随机盐值创建只进哈希
  4. 将生成的哈希值和盐值存储在NSUserDefaults 中——黑客无法使用这些值来确定原始密码,因此无需将它们存储在安全的地方。

现在,当用户输入他们的密码并且您必须验证它是否正确时,您需要执行以下操作:

  1. 从用户那里获取密码
  2. NSUserDefaults获取之前保存的哈希值+盐值
  3. 使用与加密原始密码相同的单向散列函数创建一个只进散列 - 将尝试的密码和来自NSUserDefaults 的盐值传递给它
  4. 将生成的哈希值与存储在NSUSerDefaults 中的哈希值进行比较。如果它们相同,则用户输入了正确的密码。

这是生成盐和只进哈希的代码:

NSString *FZARandomSalt(void) {
    uint8_t bytes[16] = {0};
    int status = SecRandomCopyBytes(kSecRandomDefault, 16, bytes);
    if (status == -1) {
        NSLog(@"Error using randomization services: %s", strerror(errno));
        return nil;
    }
    NSString *salt = [NSString stringWithFormat: @"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
                      bytes[0],  bytes[1],  bytes[2],  bytes[3],
                      bytes[4],  bytes[5],  bytes[6],  bytes[7],
                      bytes[8],  bytes[9],  bytes[10], bytes[11],
                      bytes[12], bytes[13], bytes[14], bytes[15]];
    return salt;
}

NSData *FZAHashPassword(NSString *password, NSString *salt) {
    NSCParameterAssert([salt length] >= 32);
    uint8_t hashBuffer[64] = {0};
    NSString *saltedPassword = [[salt substringToIndex: 32] stringByAppendingString: password];
    const char *passwordBytes = [saltedPassword cStringUsingEncoding: NSUTF8StringEncoding];
    NSUInteger length = [saltedPassword lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
    CC_SHA512(passwordBytes, length, hashBuffer);
    for (NSInteger i = 0; i < 4999; i++) {
        CC_SHA512(hashBuffer, 64, hashBuffer);
    }
    return [NSData dataWithBytes: hashBuffer length: 64];
}

此示例的代码可在此处找到:http://blog.securemacprogramming.com/2011/04/storing-and-testing-credentials-cocoa-touch-edition/

【讨论】:

    【解决方案3】:

    iPhone 上的钥匙串将是最安全的,除非您使用的是很难做到(和导出)的自定义加密。 NSUserDefaults 不被认为是安全的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-27
      • 1970-01-01
      • 1970-01-01
      • 2023-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多