如何在 iOS 应用程序中存储机密、密钥、令牌、加密密钥等关键敏感信息
Posted
技术标签:
【中文标题】如何在 iOS 应用程序中存储机密、密钥、令牌、加密密钥等关键敏感信息【英文标题】:How to store critically sensitive information such as secret, key, token, encryptionKey in iOS application 【发布时间】:2017-08-24 00:08:58 【问题描述】:当我们谈论保护 ios 应用程序时,我们经常忘记保护最关键的敏感信息,例如机密、密钥、令牌、加密密钥。此信息存储在 iOS 二进制文件中。因此,您的服务器端安全协议都不会为您提供帮助。
有很多建议我们不应该将此类信息存储在应用程序中,而应存储在服务器中并通过 SSL 安全 Web 服务调用获取。但这并非适用于所有应用程序。例如。如果我的应用程序根本不需要 Web 服务。
在 iOS 应用中,我们有以下选项来存储信息。
-
UserDefault:不适合这种情况
String 常量:不适合这种情况。可以反转
工程师检索或仅使用 strings command
安全数据库:存储在安全和加密的数据库中。 但同样有责任保护数据库用户名和密码。
KeyChain:最好存储关键信息。但我们无法在安装应用程序之前保存信息。要存储在钥匙串中,我们首先需要打开应用程序,从某个源读取并存储在钥匙串中。也不适合我们的情况。
自定义哈希字符串常量:不直接使用来自服务提供商(mixpanel、paypal)的密钥、令牌、密钥,而是使用自定义密钥中该信息的哈希版本。这也不是完美的解决方案。但是在黑客攻击过程中增加了复杂性。
请为这个问题发送一些很棒的解决方案。
【问题讨论】:
我不知道没有服务器参与的解决方案。最后,您总是需要某种秘密(私钥、秘密哈希等)来解密您在应用程序中输入的任何信息。我知道确保此信息到达您的应用程序并且只有您的应用程序使用 Apple 推送通知的唯一方法,因为该服务保证只有受信任的端点可以接收您的有效负载。不幸的是,这需要用户为您的应用启用推送通知。 可以是一种选择。 如果 iOS 和 android 为此提供了一个本地工具(例如,应用从您作为开发人员可以控制的应用商店获取的额外加密有效负载),这将是很好的,只能通过以下方式解密应用程序本身,无法通过二进制包访问。 这就是我所期待的。顺便说一句,到那时我们正在制作不安全的应用程序。 也许这可行?将秘密作为免费的应用商店托管的应用内购买内容提供给您的应用。当它被交付(由应用商店安全地,仅限于非越狱设备)到应用程序时,将其转移到钥匙串中。专业人士:最初分发时它不在您的应用程序中,因此更难发现,应用商店需要未越狱的设备。缺点:很难快速更改所有安装的密码,即使是免费的应用商店购买也可能需要用户身份验证,这对用户体验来说很麻烦。 【参考方案1】:如果您不想使用自己的后端,请使用 Apple。您可以配置 On Demand Resources 并使用您的密钥、令牌、Apple 服务器上的任何秘密保存数据文件。首次下载后,您可以将此数据写入足够安全的 Keychain。我猜 iOS 和 Apple 服务器之间的网络也足够安全。
On-Demand Resources Essentials
Accessing and Downloading On-Demand Resources
【讨论】:
是否可以保护这些秘密(例如 API 密钥)免受正在操作应用程序的攻击者的影响,并且这些秘密被存储到他们的钥匙串中?【参考方案2】:1) 需要互联网连接
1.1) 推送通知 进行安全数据交换的好方法可能是使用 Apple 的(静默)推送服务,这些服务使用 apns 并通过 https 发送数据 - 更多详情 3.1
1.2) 在向已部署的应用程序分发新用户证书时,也使用或多或少类似的方法,如果重新安装应用程序没有机会并且应用程序无论如何都需要有效的互联网连接。
缺点:需要工作网络连接,并且基本上信息会在应用程序已经执行时进入应用程序 => 似乎不适合您的情况。 (见第 4 步)
2) 静态数据(因为没有网络连接/通信伙伴就没有交换)
使用捆绑包本身提供的私钥加密数据。无论现在是字符串还是哈希,都可以使用嵌入在应用程序中的函数进行逆向工程。 由于 iOS9,反编译 iOS 应用程序非常困难,基本上您将主要查看提供的头文件。因此,如果您有这样的函数、字符串、哈希值或其他任何东西,请确保您在 .m 文件中获得了它!
但同样:如果信息不是设备或用户特定的,只是您自己的微环境中的一个秘密,在所有设备上都有效,您必须在同一个包中提供加密数据和解密方法,如果有没有更新流程/信息交换什么的,你可以想到的。
适合加密: iOS 系统安全https://developer.apple.com/reference/security 或者干脆openssl
您描述的钥匙串方法之间的区别是: 你得到了一个值,它将被加密并安全存储。 (2) 描述了加密和存储(捆绑)半安全值的方法,该值将被解密
3) 信息交流
您描述了由另一个实例散列的关键数据。伟大的! - 确保,请确保,您正在与之交谈的实例确实是您期望的实例(使用 ssl 证书固定等防止网络挂钩,但即使在这里您也可能有入侵者(中间人))。并且您将(可能)在您的应用程序包中提供一个证书,以确保通信服务器的真实性 - 再来一次,数据应该确保您的微环境的某些实例之间的安全过程。不过,这些数据是在您的应用程序包中提供的。
3.1 扩展的安全信息交换 - 无声推送 为此目的,请使用 Apple 的服务器交换您的秘密。如果您只需要交换小数据块。我建议对用户使用静默推送通知,这些通知甚至可以在没有用户明确许可的情况下工作。巨大的优势:如果您的秘密或密钥发生变化,您可以尽快通知用户有关更改。他们可能只需要在收到新数据时进行更改,这在大多数情况下应该可靠地工作。例外:在本地网络或通过蓝牙进行数据交换,在这种情况下,我建议向用户提供通知以要求更新本地解密密钥。或者也以这种格式交换密钥。再一次:我泄露了一些关于你的环境架构的详细信息。 缺点:在用户“告诉”你之前,你不知道用户是否只是第一次使用你的应用程序。 https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
3.1 扩展安全信息交换 - 应用内购买 使用免费的应用内购买让用户将数据发送到您的手机。这里的要点:您可以轻松地提供更大的数据块,因为这应该是用户的主动请求,用户确实期望一定的处理时间,并且还应该意识到需要有效的互联网连接这一事实。 缺点:用户必须故意选择它。在那之前,该应用程序将无法正常工作。 https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction.html#//apple_ref/doc/uid/TP40008267
因此,它与方法(2)的基本思想略有不同。
简而言之:您能否提供其他信息,您需要加密/想要安全存储的数据类型以及您是否将进行网络交换?
这里需要更多信息:-)
我想再次强调,iOS 上的应用程序不再那么容易解密了,即使反编译也不会得到一切,你希望它得到。例如,dumpdecrypt 等解密工具只能在 iOS 8.4 之前正常工作
【讨论】:
【参考方案3】:在我看来,最好的方法是使用内置的 CloudKit。您可以将您的秘密保存在 CloudKit Dashboard 中,然后在启动时获取它们。由于 CloudKit 只是一个传输层,您必须将应用程序机密存储在 KeyChain 中。
我知道您提到 KeyChain 不适合您的用例(不知道为什么),但这是在您的应用程序中不包含秘密的好方法。您无法绕过从其他来源获取您的应用机密。
使用系统 iCloud 帐户保护 CloudKit 访问,如果没有 iCloud 帐户,您仍然可以安全地访问 iCloud 服务器。这样做的另一个额外好处是您可以随时更改您的应用机密,因此如果您想更加安全,您可以实施轮换计划。
Learn more about CloudKit
【讨论】:
【参考方案4】:Cocoapods-keys
可能是最佳选择。
来自cocoapods-keys
文档
键名存储在 ~/.cocoapods/keys/ 和 OS X 中的键值 钥匙链。当您运行 pod install 或 pod update 时,Objective-C 类 是用加扰版本的密钥创建的,因此很难 只需转储解密二进制文件的内容并提取密钥。 在运行时,密钥会被解密以便在您的应用中使用。
生成的 Objective-C 类存储在 Pods/CocoaPodsKeys 目录,所以如果您要检查 Pods 文件夹,只需添加 Pods/CocoaPodsKeys 到你的 .gitignore 文件。 CocoaPods-Keys 支持 集成到 Swift 或 Objective-C 项目中。
查看此链接以了解安装、使用和更多信息:https://github.com/orta/cocoapods-keys
【讨论】:
这似乎是一种新方法。一定会检查的。 您找到任何(其他)解决方案了吗?【参考方案5】:我同意@Lobsterman 的观点,并相信最好的方法是结合使用这些方法。
最初不要在应用程序中包含机密信息。 将密钥作为应用内购买内容、按需资源或通过推送通知发送。如果您愿意,这将增加定期更改密钥的好处,并且更改无需任何额外工作即可生效。 在内容交付后将条目添加到钥匙串访问。【讨论】:
【参考方案6】:如果数据极其敏感,则永远不应将其离线存储在设备上,因为所有设备都是可破解的。如果您仍想在设备上存储,那么钥匙串是安全存储数据的一种选择,但它的加密基于设备的 PIN 码。用户没有强制设置密码,因此在某些情况下,数据甚至可能没有被加密。此外,用户的密码可能很容易被黑客入侵。
更好的解决方案是使用像SQLCipher 这样的东西,它是一个完全加密的 SQLite 数据库。加密密钥可以由应用程序强制执行,并与用户的 PIN 码分开。
【讨论】:
以上是关于如何在 iOS 应用程序中存储机密、密钥、令牌、加密密钥等关键敏感信息的主要内容,如果未能解决你的问题,请参考以下文章
使用身份验证令牌创建 twilio 客户端与 API 密钥和 API 机密与帐户 sid 的组合有啥区别?