在iOS应用程序场景中保护密钥,是否安全?

46

我正在尝试隐藏我在一个应用程序中使用的2个密码。

据我所知,钥匙串是一个好的选择,但在提交应用程序之前我无法添加它们。

我考虑了这种情况 -

  • 通过将它们分散在其他实体中来预先放置我的应用程序的CoreData数据库中的密钥。 (我已经在该应用程序中有一个种子数据库)。
  • 当应用程序首次启动时,生成并将密钥移动到钥匙串中。
  • 从CoreData中删除记录。

这样安全吗?黑客能否看到这一过程并获取这些密钥?

*第三次编辑** 很抱歉没有从一开始就解释清楚这种情况 - 应用程序有许多级别,每个级别都包含文件(音频,视频,图像)。用户可以购买级别(IAP),购买完成后,我需要将文件下载到他的设备上。

对于iOS6,文件使用苹果的新“托管内容”功能存储。 对于iOS5,文件存储在亚马逊S3中。

因此,在整个过程中,我有两个密钥: 1. IAP密钥,用于验证在Apple IAP上的购买。 2. S3密钥,用于获取iOS5用户的S3文件:

NSString *secretAccessKey = @"xxxxxxxxx";
NSString *accessKey = @"xxxxxxxxx";

我需要保护这些密钥吗?我担心人们在未购买级别的情况下能够从S3获取文件,或者黑客能够构建一个预先下载了所有级别的破解版本。


秘密是以何种方式使用的?是用于客户端和服务器之间的通信吗?还是安全地存储设备上的文件?了解保护某物的原因可以帮助建议实现它的最佳方法。 - WDUK
1
你能否提供更多关于为什么需要保护这些S3密钥的信息?我理解得对吗,你希望这些文件只能被你应用程序的用户访问?你通过IAP出售对这些文件的访问权限,你担心人们会未经付款就下载并开始使用它们? - Victor Ronin
2
此外,您要保护自己免受谁的攻击?是合法的应用程序用户(购买了应用程序,通过IAP付款,现在正在尝试破解应用程序),还是非法用户(某人能够从某处获取您的应用程序.ipa文件,现在正在尝试破解您的应用程序并获取其中的密钥)。有更多的方法来保护自己免受非法用户的攻击(相对于合法用户)。 - Victor Ronin
@VictorRonin 再次编辑,解释了购买场景。 - shannoga
3个回答

75

让我尝试将您的问题细分为多个子问题/假设:

假设:

a) Keychain 是安全的地方

实际上,并不那么安全。如果您的应用程序安装在越狱设备上,黑客将能够从 keychain 中获取您的密钥。

问题:

a) 有没有办法将某些密钥放入应用程序(从 AppStore 提供的二进制文件)中并完全安全?

简短的答案是否定的。只要二进制文件中有任何东西,它就可能被反向工程。

b) 混淆是否有帮助?

是的。它将增加黑客找到答案的时间。如果您在应用程序中拥有的密钥的“成本”比反向工程所需的时间少 - 一般而言,您就安全了。

但是,在大多数情况下,安全通过混淆是不好的实践。它让你觉得你很安全,但实际上你并不安全。

因此,这可能是安全措施之一,但您需要采取其他安全措施。

c) 在这种情况下应该怎么做?*

在不知道您要做什么的背景下,很难为您提供一个好的解决方案。

例如,为什么每个人都应该访问同一个 Amazon S3?他们需要只读还是写(如 Kendall Helmstetter Gein 指出的那样)。

我认为最安全的情况之一可能是:

  • 您的应用程序应该受到密码保护
  • 第一次进入应用程序时,它会请求用户进行身份验证(输入用户名、密码)到服务器
  • 这将对您的服务器或其他身份验证提供程序进行身份验证(例如 Google)
  • 服务器向设备发送某些身份验证令牌(通常是某种类型的 cookie)。
  • 您根据应用程序密码的哈希值加密此令牌,并以此形式保存在 keychain 中
  • 现在你可以做以下两件事之一:
  • 将特定的密钥从服务器交给客户端(这样每个客户端都有自己的密钥),并使用应用程序密码哈希加密它们
  • 在服务器上处理所有与S3的操作(并要求客户端发送)
  • 这种方法可以保护您免受多种可能的攻击。

    c) 哇哦....我不打算实现你刚才写的所有东西,因为这将花费我的数月时间。有更简单的方法吗?

    如果每个客户端都有一组密钥,那么这将是有用的。

    如果即使这也太麻烦了,那么就从服务器下载加密的密钥,并以加密形式保存在设备上,并在应用程序中硬编码解密密钥。我会说这是最低侵入性的,至少你的二进制文件里没有密钥。

    P.S. Kendall和Rob都是对的。

    更新1(基于新信息)

    首先,您看过应用内购买编程指南吗?

    在服务器产品模型下有非常好的绘图。这个模型可以防止未购买新级别的人。你的应用程序中不会嵌入任何亚马逊密钥,当它收到购买收据时,你的服务器端将交付级别。

    没有完美的解决方案来防止某些人(购买了内容并决定从您的应用程序中删除它)的情况,因为在最后一天,您的应用程序将下载到设备上,并且在某个时间点需要以明文(未加密形式)使用它。

    如果您真的担心这种情况,我建议您加密所有资产,并以加密形式从服务器交付它们和加密密钥。每个客户端都应该生成一个加密密钥,并使用它来加密资产。

    这不会阻止任何高级黑客,但至少它会保护免受某些人使用iExplorer并只复制文件的攻击(因为它们将被加密)。

    更新2

    关于更新1,还有一件事情需要注意。你应该将文件以未加密的形式存储,并将加密密钥存储在某个地方(例如钥匙串)。

    如果你的游戏需要联网,则最好不要在设备上存储加密密钥。每次启动应用程序时,可以从服务器获取该密钥。


关于更新2:您需要一个加密密钥才能从服务器获取加密密钥。 - Thi
你所说的“密码保护”是指将密码存储在二进制文件中,然后使用其哈希作为对称密钥来访问令牌吗?还是指最终用户必须输入的实际密码? - Þorvaldur Rúnarsson
还有一件事。这个是在保护什么,听起来像是在保护令牌的存储,但这并没有太大的区别,因为中间人攻击会暴露发送到应用程序的令牌。 - Þorvaldur Rúnarsson
@ÞorvaldurRúnarsson 我的意思是指最终用户输入的密码。 - Victor Ronin
@ÞorvaldurRúnarsson 您说得完全正确。在越狱设备上,一切都可以被拦截(输入密码、解密令牌等等)。因此,没有绝对安全的方法。然而,我所描述的方法比从二进制文件中提取硬编码密钥需要更多时间。问题是数据有多么有价值。 - Victor Ronin

17

不要在应用程序中存储用于写入的S3密钥!简单来说,任何窃听流量的人都会看到向S3发出的写入调用,而很快他们就会找到该密钥并执行任何他们想做的操作。

应用程序能够以任何安全程度将内容写入S3的唯一方法是通过您控制的服务器。

如果这是一个仅用于只读使用的密钥,也就是说,您的S3不能被公开读取,但可以使用该密钥进行只读访问而没有写入权限,那么您可以将其嵌入到应用程序中,但任何想要获取它的人都可以提取它。

为了轻微混淆预加载的敏感数据,您可以将其加密在文件中,应用程序可以将其读入内存并在存储在键链之前进行解密。同样,有人将能够获得这些密钥,因此最好不要过于关注他们是否能够获取。

编辑:

根据新信息,您最好只需将秘密嵌入代码中。使用像iExplorer这样的工具,普通用户可以轻松地访问核心数据数据库或应用程序包中的任何其他内容,但对象文件有点加密。如果他们有越狱的设备,他们可以轻松获得未加密版本,但仍然可能很难找到有意义的字符串,也许将它们分成两部分并在代码中重新组装。

再次强调,这不能阻止一个决心的黑客,但足以阻止大多数人。

您还可以添加一些代码,尝试询问服务器是否有任何覆盖秘密可供下载。这样,如果秘密泄漏,您可以快速反应,更改用于应用程序的秘密,同时排除使用复制的秘密的任何人。首先不会有任何覆盖要下载。您不希望等待应用程序更新才能使用新密钥。


11

在向攻击者发送的代码中隐藏秘密没有好的方法。就像大多数此类事情一样,你需要更加关注如何在密钥泄露时减轻问题,而不是花费无限的时间来保护它。例如,为每个用户生成不同的密钥允许你禁用滥用使用的密钥。或者通过中间服务器工作,可以控制协议(即服务器拥有密钥并且只愿意执行特定操作)。

稍微模糊化一下并不是浪费时间。这很好。但不要花太多时间在上面。如果它在程序中且非常有价值,那么它将被破解出来。重点是如何检测发生这种情况以及如何在出现问题时进行恢复。尽可能将这种敏感数据移动到你控制的其他服务器上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接