Apple 在 iOS 中是否有一种方法可以安全地向 9.3 或更高版本上同一 iOS 应用程序的所有实例提供来自 public/private 密钥对的服务?
Does Apple have a method in iOS to securely provide the services from a public/private key pair to all instances of the same iOS app on 9.3 or later?
什么是安全地为跨不同设备的应用程序的所有实例提供 public/private 密钥对的有效方法,该密钥对将用于加密和解密创建的任何这些数据记录设备,以便任何设备上的任何应用程序实例都可以解密使用这些密钥加密的记录?
特别是,这是针对 9.3 或更高版本上的基于云的 iOS 应用程序,该应用程序在某些专有的基于云的服务器中存储极其敏感的信息。然而,我们不希望我们自己的云服务器拥有私钥,以消除如果我们的主服务器被黑客入侵时密钥被泄露的可能性。
我希望有一种方法,例如让 Apple 在应用程序安装时向系统钥匙串中注入一个通用密钥,这样 Apple 安全堡垒本身之外的任何人都无法看到私钥,而且它会与设备的系统钥匙串一样安全。
我所知道的用于存储将在同一应用程序的所有实例中访问的私钥的现有选项:
(1) 将密钥对硬编码到应用程序中。
垮台:如果有人可以访问代码存储库,and/or 充分反编译应用程序,他们就可以重建私钥。
(2) 让设备通过 CloudKit 连接到 iCloud 并从应用程序的 public 容器中提取密钥对,然后将其存储到系统钥匙串中。 失败:破坏正确 AppleID 凭据的攻击者可以访问解密数据所需的一切。此外,Apple 最新的安全白皮书称应用程序的 public iCloud 容器是 "not encrypted"。
(3) 让应用程序要求安装包含证书的配置文件。 失败:配置文件的来源可能为攻击者所有。
(4) 1 到 3 的组合:assemble 启动时的私钥来自一堆硬编码的点点滴滴,来自 iCloud,来自一些。垮台:通过让攻击者跳过更多障碍来减少垮台并不是没有垮台。
(5) 有五吗?
我理想中想要的 是 Apple 提供的在应用程序安装时将特殊密钥对注入设备系统密钥链的方法,这样:
应用程序本身在密钥注入中发挥作用,这将在应用程序启动之前完成
应用程序本身无法直接访问密钥对
应用程序所能做的就是将事情传递给系统框架来处理 signing/encrypting/decrypting 依赖于这些键的操作
此密钥对不适用于未经 Apple 签名的应用程序版本(即 beta/dev/QA 版本依赖代理证书)
应用程序的所有副本都来自相同的密钥对
开发人员可以重置密钥对,此时应用程序的后续更新可以让系统对数据进行一次性转换,从使用旧密钥加密到使用旧密钥加密新的
...苹果有提供这样的方法吗?或者其他人?
编辑:有关该方法的更多详细信息。
第 1 步:使用 OpenSSL 生成一组密钥对,K1 到 KN,其中 N是数据加密的总层数,命令如下:
openssl genrsa -aes256 -out NPrivateKey.pem 2048
openssl rsa -in NPrivateKey.pem -out NPrivateKeyOpen.pem -outform PEM
openssl rsa -in NPrivateKey.pem -pubout -out NPublicKey.pem -outform PEM
第 2 步:将每个密钥拆分为多个 F 个单独的文件。这些是 片段。
第三步:用KN+1加密KN的每个片段(K1未加密)。
步骤 4:创建策略 S1 到 SN 来打乱 K1[=79 片段的顺序=] 到 KN 这样它们就可以在运行时由应用程序通过算法重新组合成原始密钥,假设它知道 N 对于给定的 K(如果需要,它如何知道 N 可以通过完全独立的过程处理)。此步骤允许片段以打乱的形式存在于内存中,以获得额外的模糊度(对于它的价值)。这里的目标只是在潜在攻击者的路径上设置尽可能多的障碍。例如,如果密钥的任何方面一起存储在某个地方的磁盘上(例如在回购或公司密钥保管库等中),这往往会挫败扫描数据卷的简单尝试,例如,使用正则表达式序列来识别存储在磁盘上的密钥。如果我们被打败了,那就不要被脚本小子打败了——知道我在说什么吗?
第 5 步:创建一个策略 D1 到 DN 以分配片段,以便应用可以收集所有片段运行。
第 6 步:如果任何片段存储在应用程序的代码本身中,则应使用尽可能最隐蔽的形式存储它们,例如一组 纯 算法函数调用,可以输出密钥但将密钥的 没有部分 存储为字符串文字。用于这种模糊的策略是 O1 到 ON,并且哪个模糊策略用于哪个片段哪个键也根据策略进行洗牌OS。 (使用像 Objective C 这样的语言的方法调配和动态运行时特性在这里可以用来创建一些有趣的技巧来击败任何附加调试器来告诉到底发生了什么的人;当然,发行版构建应该总是拒绝调试器连接,但这超出了这个答案的范围。)
第 7 步:实现上述策略的任何方面或存储任何模糊的关键片段的代码库的所有部分应该永远不会出现在任何 提交到项目的主要代码存储库。 Git 过滤器应该与脚本一起使用(是时候玩 Swift shell 脚本了!)来涂抹和清理所有此类代码。一个完全独立的存储库应该在存储在物理保险箱中的加密驱动器上维护,只有在需要重新编译相关静态 library/objects 时才会取出。这样即使有人获得了 github 帐户(或其他)的访问权限,他们也不会获得策略或片段的访问权限。
第 8 步:不要在系统钥匙串中存储任何钥匙。我们之前已经看到 iOS 的系统钥匙串遭到破坏。 Whosebug 上的其他答案可以指导您如何使用私钥解密 iOS 上的数据,而私钥永远不会进入系统钥匙串。也许这是一个值得商榷的问题,因为一旦将密钥放入钥匙串中,就可以将其从钥匙串中删除,并且为了更加隐蔽,您可以像我们那样做,只存储 some of堆栈中的密钥在那里,并存储一些加密的片段,就好像它们是密码哈希等(所有这些都更加晦涩难懂,导致人们走上错误的道路和可能试图打破它的混乱迷宫)。
同样,我当然毫不怀疑在技术上 可能 击败这种(或任何)形式的加密;然而,目标只是为潜在的攻击者提供尽可能陡峭的爬坡,但最终让多个客户端能够共享相同的私钥。
请参阅我在开发上述解决方案后发现的文章 Secure Key Distribution Using Fragmentation and Assimilation in Wireless Sensor and Actor Networks。 Ghafoor 等人的 "KDFA" 方法在很多方面与我上面描述的方法相似。
此外,请注意,我相信任何实施此类解决方案的人都会意识到,在这个过程中有很多点可以(并且应该)插入额外的模糊和加密层;这个答案的目的只是描述该方法的大致思路。细节决定成败,确切地说,如何实施此方法可能会提高或降低其安全性。
此外,当然,我相信不言而喻,分发策略中涉及的所有基于网络的通信都必须使用 TLS 1.2 w/PFS(或者任何新的最好的东西)来保护将来阅读此书)。当然,除了 共享私钥之外,还应该使用 其他特定于个人客户端的私钥。当然,在各个方面都遵守了所有正常的最佳实践。
然而,即使我们遵循所有最佳实践,如何将相同的密钥分发到一组设备,以便只有客户端,而不是服务器,才能解密数据,这就是问题所在。我们一次又一次地看到,无论客户端多么安全,如果有人拥有服务器,那么狐狸就会得到鸡舍里的所有鸡蛋。然而,如果服务器只是一个完全加密数据的存储设施,并且客户端使用足够动态和复杂的方法来 encrypt/decrypt 该数据,那么它往往有助于解决 "what if the server gets owned" 和 "what if the code repository gets owned"等
现在,如果上述方法有任何重大缺陷,那么我当然很乐意听到,以便可以改进。
我刚刚拿到了两个密钥对。其中一个我用来加密另一个。然后我将加密的形式分解成许多碎片并将它们存放在各处......在云中......在服务器上......在我的应用程序上的混淆字符串中......等等
None 的加密涉及的字符串或密钥在编译后的应用程序中是字符串或二进制格式。它都是以一种相当模糊的方式通过编程生成的。
在运行时,我们使用神秘的数学函数来构建调用应用程序周围隐藏方法的方法名称 assemble 第一个密钥,然后我们从整个互联网上获取第二个密钥的加密碎片,然后用第一个密钥解密它们,然后我们使用第二个密钥解密重要的客户端数据。
然后我们使用一种特殊的 sauce 方法,其中 none 涉及此混淆的代码位于我们存储库中的任何位置。它在特定时间动态加载。 :D 这就是我要说的。
什么是安全地为跨不同设备的应用程序的所有实例提供 public/private 密钥对的有效方法,该密钥对将用于加密和解密创建的任何这些数据记录设备,以便任何设备上的任何应用程序实例都可以解密使用这些密钥加密的记录?
特别是,这是针对 9.3 或更高版本上的基于云的 iOS 应用程序,该应用程序在某些专有的基于云的服务器中存储极其敏感的信息。然而,我们不希望我们自己的云服务器拥有私钥,以消除如果我们的主服务器被黑客入侵时密钥被泄露的可能性。
我希望有一种方法,例如让 Apple 在应用程序安装时向系统钥匙串中注入一个通用密钥,这样 Apple 安全堡垒本身之外的任何人都无法看到私钥,而且它会与设备的系统钥匙串一样安全。
我所知道的用于存储将在同一应用程序的所有实例中访问的私钥的现有选项:
(1) 将密钥对硬编码到应用程序中。 垮台:如果有人可以访问代码存储库,and/or 充分反编译应用程序,他们就可以重建私钥。
(2) 让设备通过 CloudKit 连接到 iCloud 并从应用程序的 public 容器中提取密钥对,然后将其存储到系统钥匙串中。 失败:破坏正确 AppleID 凭据的攻击者可以访问解密数据所需的一切。此外,Apple 最新的安全白皮书称应用程序的 public iCloud 容器是 "not encrypted"。
(3) 让应用程序要求安装包含证书的配置文件。 失败:配置文件的来源可能为攻击者所有。
(4) 1 到 3 的组合:assemble 启动时的私钥来自一堆硬编码的点点滴滴,来自 iCloud,来自一些。垮台:通过让攻击者跳过更多障碍来减少垮台并不是没有垮台。
(5) 有五吗?
我理想中想要的 是 Apple 提供的在应用程序安装时将特殊密钥对注入设备系统密钥链的方法,这样:
应用程序本身在密钥注入中发挥作用,这将在应用程序启动之前完成
应用程序本身无法直接访问密钥对
应用程序所能做的就是将事情传递给系统框架来处理 signing/encrypting/decrypting 依赖于这些键的操作
此密钥对不适用于未经 Apple 签名的应用程序版本(即 beta/dev/QA 版本依赖代理证书)
应用程序的所有副本都来自相同的密钥对
开发人员可以重置密钥对,此时应用程序的后续更新可以让系统对数据进行一次性转换,从使用旧密钥加密到使用旧密钥加密新的
...苹果有提供这样的方法吗?或者其他人?
编辑:有关该方法的更多详细信息。
第 1 步:使用 OpenSSL 生成一组密钥对,K1 到 KN,其中 N是数据加密的总层数,命令如下:
openssl genrsa -aes256 -out NPrivateKey.pem 2048
openssl rsa -in NPrivateKey.pem -out NPrivateKeyOpen.pem -outform PEM
openssl rsa -in NPrivateKey.pem -pubout -out NPublicKey.pem -outform PEM
第 2 步:将每个密钥拆分为多个 F 个单独的文件。这些是 片段。
第三步:用KN+1加密KN的每个片段(K1未加密)。
步骤 4:创建策略 S1 到 SN 来打乱 K1[=79 片段的顺序=] 到 KN 这样它们就可以在运行时由应用程序通过算法重新组合成原始密钥,假设它知道 N 对于给定的 K(如果需要,它如何知道 N 可以通过完全独立的过程处理)。此步骤允许片段以打乱的形式存在于内存中,以获得额外的模糊度(对于它的价值)。这里的目标只是在潜在攻击者的路径上设置尽可能多的障碍。例如,如果密钥的任何方面一起存储在某个地方的磁盘上(例如在回购或公司密钥保管库等中),这往往会挫败扫描数据卷的简单尝试,例如,使用正则表达式序列来识别存储在磁盘上的密钥。如果我们被打败了,那就不要被脚本小子打败了——知道我在说什么吗?
第 5 步:创建一个策略 D1 到 DN 以分配片段,以便应用可以收集所有片段运行。
第 6 步:如果任何片段存储在应用程序的代码本身中,则应使用尽可能最隐蔽的形式存储它们,例如一组 纯 算法函数调用,可以输出密钥但将密钥的 没有部分 存储为字符串文字。用于这种模糊的策略是 O1 到 ON,并且哪个模糊策略用于哪个片段哪个键也根据策略进行洗牌OS。 (使用像 Objective C 这样的语言的方法调配和动态运行时特性在这里可以用来创建一些有趣的技巧来击败任何附加调试器来告诉到底发生了什么的人;当然,发行版构建应该总是拒绝调试器连接,但这超出了这个答案的范围。)
第 7 步:实现上述策略的任何方面或存储任何模糊的关键片段的代码库的所有部分应该永远不会出现在任何 提交到项目的主要代码存储库。 Git 过滤器应该与脚本一起使用(是时候玩 Swift shell 脚本了!)来涂抹和清理所有此类代码。一个完全独立的存储库应该在存储在物理保险箱中的加密驱动器上维护,只有在需要重新编译相关静态 library/objects 时才会取出。这样即使有人获得了 github 帐户(或其他)的访问权限,他们也不会获得策略或片段的访问权限。
第 8 步:不要在系统钥匙串中存储任何钥匙。我们之前已经看到 iOS 的系统钥匙串遭到破坏。 Whosebug 上的其他答案可以指导您如何使用私钥解密 iOS 上的数据,而私钥永远不会进入系统钥匙串。也许这是一个值得商榷的问题,因为一旦将密钥放入钥匙串中,就可以将其从钥匙串中删除,并且为了更加隐蔽,您可以像我们那样做,只存储 some of堆栈中的密钥在那里,并存储一些加密的片段,就好像它们是密码哈希等(所有这些都更加晦涩难懂,导致人们走上错误的道路和可能试图打破它的混乱迷宫)。
同样,我当然毫不怀疑在技术上 可能 击败这种(或任何)形式的加密;然而,目标只是为潜在的攻击者提供尽可能陡峭的爬坡,但最终让多个客户端能够共享相同的私钥。
请参阅我在开发上述解决方案后发现的文章 Secure Key Distribution Using Fragmentation and Assimilation in Wireless Sensor and Actor Networks。 Ghafoor 等人的 "KDFA" 方法在很多方面与我上面描述的方法相似。
此外,请注意,我相信任何实施此类解决方案的人都会意识到,在这个过程中有很多点可以(并且应该)插入额外的模糊和加密层;这个答案的目的只是描述该方法的大致思路。细节决定成败,确切地说,如何实施此方法可能会提高或降低其安全性。
此外,当然,我相信不言而喻,分发策略中涉及的所有基于网络的通信都必须使用 TLS 1.2 w/PFS(或者任何新的最好的东西)来保护将来阅读此书)。当然,除了 共享私钥之外,还应该使用 其他特定于个人客户端的私钥。当然,在各个方面都遵守了所有正常的最佳实践。
然而,即使我们遵循所有最佳实践,如何将相同的密钥分发到一组设备,以便只有客户端,而不是服务器,才能解密数据,这就是问题所在。我们一次又一次地看到,无论客户端多么安全,如果有人拥有服务器,那么狐狸就会得到鸡舍里的所有鸡蛋。然而,如果服务器只是一个完全加密数据的存储设施,并且客户端使用足够动态和复杂的方法来 encrypt/decrypt 该数据,那么它往往有助于解决 "what if the server gets owned" 和 "what if the code repository gets owned"等
现在,如果上述方法有任何重大缺陷,那么我当然很乐意听到,以便可以改进。
我刚刚拿到了两个密钥对。其中一个我用来加密另一个。然后我将加密的形式分解成许多碎片并将它们存放在各处......在云中......在服务器上......在我的应用程序上的混淆字符串中......等等
None 的加密涉及的字符串或密钥在编译后的应用程序中是字符串或二进制格式。它都是以一种相当模糊的方式通过编程生成的。
在运行时,我们使用神秘的数学函数来构建调用应用程序周围隐藏方法的方法名称 assemble 第一个密钥,然后我们从整个互联网上获取第二个密钥的加密碎片,然后用第一个密钥解密它们,然后我们使用第二个密钥解密重要的客户端数据。
然后我们使用一种特殊的 sauce 方法,其中 none 涉及此混淆的代码位于我们存储库中的任何位置。它在特定时间动态加载。 :D 这就是我要说的。