简体   繁体   English

苹果在iOS中是否有一种方法可以安全地从9.3或更高版本的公钥/私钥对向同一iOS应用的所有实例提供服务?

[英]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?

What is a valid method to securely provide all instances of an app across different devices with a public/private key pair that would be used both to encrypt and decrypt data records created any of those devices, such that any instance of the app on any device can decrypt the records encrypted with those keys? 一种有效的方法可以安全地为不同设备上的应用程序的所有实例提供一个公钥/私钥对,该公钥/私钥对将用于加密和解密在任何设备上创建的数据记录,从而使任何设备上的应用程序的任何实例可以解密用那些密钥加密的记录吗?

In particular, this is for a cloud-based iOS app on 9.3 or later that stores extremely sensitive information in some proprietary cloud-based servers. 特别是,这适用于9.3或更高版本上的基于云的iOS应用程序,该应用程序在某些专有的基于云的服务器中存储极其敏感的信息。 We don't want our own cloud server having the private key however, to eliminate the possibility of the key being leaked should our main server get hacked. 但是,我们不希望自己的云服务器具有私钥,以消除万一我们的主服务器被黑客入侵,密钥被泄露的可能性。

I was hoping there'd be a way for example to have Apple inject a common key to the system keychain at app install, so that no human outside of Apple's security fortress itself could see the private keys, and it would be as secure as the device's system keychain. 我希望有一种方法,例如让Apple在应用程序安装时向系统钥匙串注入一个公共密钥,这样,苹果安全堡垒之外的任何人都不会看到私钥,并且它会像设备的系统钥匙串。


Existing options that I know about for storing a private key that would be accessed across all instances of the same app : 我所知道的用于存储私钥的现有选项可以在同一应用的所有实例之间进行访问

(1) Hard-code a key-pair right into the app. (1) 将密钥对硬编码到应用中。 Downfall: If someone gets access to the code repository, and/or sufficiently decompiles the app, they can reconstruct the private key. 崩溃:如果有人可以访问代码存储库和/或充分反编译应用程序,则他们可以重构私钥。

(2) Have the device connect to iCloud via CloudKit and pull down the key-pair from the app's public container, then store it into the system keychain. (2) 让设备通过CloudKit连接到iCloud,并从应用程序的公共容器中拉出密钥对,然后将其存储到系统密钥链中。 Downfall: an attacker who compromises the right AppleID credentials could gain access to everything needed to decrypt the data. 崩溃:攻击者可以通过使用正确的AppleID凭据进行攻击,来访问解密数据所需的所有内容。 Also, Apple's latest security white paper says an app's public iCloud container is "not encrypted". 另外,苹果公司最新的安全白皮书说,应用程序的公共iCloud容器“未加密”。

(3) Have the app require a configuration profile be installed that contains the certs. (3) 让应用程序要求安装包含证书的配置配置文件。 Downfall: the source of the configuration profile could be owned by an attacker. 失败:攻击者可能拥有配置配置文件的来源。

(4) Combination of 1 through 3: assemble the private key at launch time from a bunch of bits and pieces that are hard-coded, come from iCloud, and come from some. (4) 1到3的组合:在启动时,从一堆硬编码的,来自iCloud的和来自一堆的零碎的片段中组装私钥。 Downfall: less downfall by making an attacker jump over more hurdles is not no downfall . 崩溃:通过使攻击者越过更多的障碍来减少崩溃并不是没有崩溃

(5) Is there a five? (5)有五个吗?


What I want ideally is an Apple-provided way to inject a special key-pair into the system keychain of the device at the time of app install, such that that: 我理想地想要的是Apple提供的一种方法,该方法是在应用安装时向设备的系统钥匙串中注入特殊的密钥对,从而:

  • the app itself has role in the key injection, which would be done prior to the app launching 应用程序本身在密钥注入中起作用,这将在应用程序启动之前完成

  • the app itself has no direct access to the key pair 应用本身无法直接访问密钥对

  • all the app can do is pass things to a system framework to handle signing/encrypting/decrypting operations that rely on these keys 该应用程序所能做的就是将事物传递给系统框架,以处理依赖于这些密钥的签名/加密/解密操作

  • this key-pair is not available to versions of the app that are not signed by Apple (ie beta/dev/QA versions rely on proxy certs) 此密钥对不适用于未由Apple签名的应用程序版本(即beta / dev / QA版本取决于代理证书)

  • all copies of the app the same results from the same key-pair 该应用程序的所有副本均来自相同的密钥对

  • the developer can reset the key-pair, at which point subsequent updates of the app can have the system do a one-time transition of data from being encrypted with the old key to being encrypted with the new one 开发人员可以重置密钥对,这时应用程序的后续更新可以使系统执行一次从旧密钥加密到新密钥加密的一次性数据转换。

... does Apple provide such a method? ...苹果提供这种方法吗? Or anyone else? 还是其他人?

EDIT: More details on the method. 编辑:有关该方法的更多详细信息。

Step 1: Use OpenSSL to generate a set of keypairs, K1 through KN , where N is the total number of layers of encryption on the data, with the following command: 步骤1:使用以下命令,使用OpenSSL生成一组密钥对,即K1KN ,其中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

Step 2: Split up each key into a number F of separate files. 步骤2:将每个密钥分为多个F个单独的文件。 These are the fragments . 这些是碎片

Step 3: Encrypt each fragment of KN with KN+1 ( K1 does not get encrypted). 步骤3:使用KN + 1加密KN的每个片段( K1不会被加密)。

Step 4: Create strategies S1 through SN for shuffling the order of the fragments of K1 through KN such that they can be algorithmically recombined into the original key by the app at runtime, assuming it knows N for a given K (how it knows N can be handled through an entirely separate process, if desired). 步骤4:通过KN,使得它们可以通过算法重新组合成在运行时由应用程序的原始密钥洗牌K1的片段的顺序创建通过SN策略S1,假设它知道N代表一个给定的K(它是如何知道n可以如果需要,则通过完全独立的过程进行处理)。 This step allows for the fragments to exist in memory in a shuffled form for an additional degree of obscurity (for what it's worth). 此步骤允许片段以改组的形式存在于内存中,从而增加了晦涩感(这是值得的)。 The goal here is simply to erect as many hurdles as possible in the path of a would-be attacker. 此处的目标仅仅是在潜在攻击者的路径上建立尽可能多的障碍。 For example if any aspects of the key were stored together on disk somewhere (for example in a repo or corporate key vault, etc.) this would tend to defeat simple attempts to scan a data volume, for example, using a regex sequence to identify keys stored on disk. 例如,如果密钥的任何方面一起存储在磁盘上的某个位置(例如,存储在仓库或公司密钥库中,等等),这将倾向于打败简单的尝试扫描数据量的尝试,例如使用正则表达式序列来识别密钥存储在磁盘上。 If we are defeated, let it not be by a script kiddie—know what I'm saying? 如果我们被打败了,那就别被脚本小子打败了-知道我在说什么吗?

Step 5: Create a strategy D1 through DN for the distribution of the fragments such that the app can collect all the fragments at runtime. 步骤5:创建策略D1DN ,以分配片段,以便应用程序可以在运行时收集所有片段。

Step 6: Should any fragments be stored in the app's code itself they should be stored using the strongest possible form of obscurity, eg a set of purely algorithmic function calls that can output the key but that store no part of the key as a string literal. 步骤6:如果将任何片段存储在应用程序的代码本身中,则应使用最强的模糊形式存储它们,例如,一组算法函数调用,可以输出密钥,但不存储任何部分作为字符串文字。 The strategy used for this obscurity would be O1 through ON , and which obscurity strategy is used for which fragment for which key is also shuffled according to strategy OS . 用于这种模糊处理的策略将是O1ON ,并且该模糊处理策略用于根据策略OS对其密钥也进行改组的片段。 (The use of method swizzling and dynamic runtime features of a language like Objective C can be useful here in creating some fun tricks to defeat anyone who gets a debugger attached to tell what the heck is going on; of course the distribution builds should always reject debugger connections, but that is out of scope for this answer.) (使用Objective C这样的方法的方法混乱和动态运行时功能可以在此处创建一些有趣的技巧,以击败那些附加了调试器以告知到底发生了什么事情的人;当然,发行版本应该始终拒绝调试器连接,但这超出了此答案的范围。)

Step 7: All sections of the codebase implementing any aspects of the above strategies or storing any obscured key fragments should never ever appear in any commits to the primary code repository for the project. 步骤7:代码库的所有部分实现上述战略的任何其他方面或存储任何遮挡的关键片段永远都不应出现在任何提交至项目的主代码库。 Git filters should be used in tandem with scripts (time for fun with Swift shells scripts!) to smudge and clean all such code. Git过滤器应与脚本(使用Swift shell脚本玩得开心!)一起使用,以弄脏并清理所有此类代码。 A completely separate repository should be maintained on an encrypted drive stored in a physical safe, that is only brought out when the relevant static library/objects need to be recompiled. 完全独立的存储库应保存在存储在物理保险箱中的加密驱动器上,只有在需要重新编译相关的静态库/对象时才将其导出。 That way even if someone gains access to the github account (or whatever) they will not gain access to the strategies or fragments. 这样,即使有人可以访问github帐户(或其他任何方式),他们也不会访问策略或片段。

Step 8: Do not store any keys in the system keychain. 步骤8:请勿在系统钥匙串中存储任何钥匙。 We have seen iOS's system keychain be compromised before. 我们之前已经看到过iOS的系统钥匙串遭到破坏。 Other answers on StackOverflow can guide you on how to use a private key to decrypt data on iOS without the private key ever going into the system keychain. StackOverflow上的其他答案可以指导您如何使用私钥在iOS上解密数据,而无需私钥进入系统钥匙串。 Perhaps this is a debatable point since the key could be deleted out of the keychain as soon as it's put in there, and for extra obscurity, you could do like we did and only store some of the keys in the stack in there, and store some of the encrypted fragments as if they were password hashes, etc. (all just more obscurity to lead people down false paths and confusing mazes that might try to break it). 也许这是一个值得商point的问题,因为一旦将钥匙放入钥匙串中就可以将其从钥匙串中删除,而且为了使您更加了解,您可以像我们所做的那样,只将一些钥匙存放在该钥匙串中,然后进行存储一些加密的片段,就好像它们是密码哈希一样,等等(只是更加模糊,导致人们误入虚假路径并迷惑可能试图破解它的迷宫)。

Again, of course I have no doubt that it's technically possible to defeat this (or any) form of encryption; 同样,毫无疑问,毫无疑问,从技术上讲, 可以打破这种(或任何一种)加密形式。 however the goal is simply to provide as steep of a hill to climb as is reasonably possible for a would-be attacker, yet ultimately have multiple clients be able to share the same private key. 但是,目标只是为可能的攻击者提供尽可能合理的尽可能陡峭的山坡,而最终使多个客户端能够共享相同的私钥。

Please refer to the article, Secure Key Distribution Using Fragmentation and Assimilation in Wireless Sensor and Actor Networks , which I discovered after developing the above solution. 请参阅在开发上述解决方案后发现的文章“ 在无线传感器和Actor网络中使用分段和同化进行安全密钥分发” Ghafoor et al.'s "KDFA" method is in many respects similar to what I have described above. Ghafoor等人的“ KDFA”方法在很多方面与我上面描述的相似。

Also, please note that I'm sure anyone implementing such a solution as this will realize that there are many points in the process where additional layers of obscurity and encryption can (and should) be interjected; 另外,请注意,我敢肯定,实施此解决方案的任何人都将意识到,在过程中有很多点可以(并且应该)插入其他层次的晦涩和加密。 the goal of this answer is merely to describe the broad strokes of the method. 该答案的目的仅仅是描述该方法的广泛应用。 The devil is in the details, and precisely how this method is implemented could make it more, or less secure. 魔鬼在细节,正是如何实现此方法是可以使更多或更少的安全。

Also, of course, I believe it goes without saying that all network-based communication involved in the distribution strategies must be secured with TLS 1.2 w/PFS (or whatever the new best thing is when ever you are reading this in the future). 同样,当然,我相信不用说,分发策略中涉及的所有基于网络的通信都必须使用TLS 1.2 w / PFS(或将来阅读时的新事物)来确保安全。 Of course, further individual-client-specific private keys should be used on top of the shared private key. 当然,应该在共享私钥的基础使用其他特定于个人客户端的私钥。 Of course, all the normal best practices in every regard are observed. 当然,所有方面都遵循所有正常的最佳做法。

However the issue of how to distribute the same key to a group of devices such that only the clients, but not the server, can decrypt the data, is the problem, even if we follow all the best practices. 但是,即使我们遵循所有最佳实践,如何将同一密钥分配给一组设备,使得只有客户端(而不是服务器)才能解密数据的问题才是问题。 What we have seen time and time again is that no matter how secure clients are, if someone owns the server then the fox gets all the eggs in the hen house. 我们一次又一次看到的是,无论客户端有多安全,如果有人拥有服务器,那么狐狸就会在鸡舍中获取所有鸡蛋。 However if the server is merely a storage facility for totally encrypted data and the client employs a sufficiently dynamic and complex method to encrypt/decrypt that data, then it tends to help the concern of "what if the server gets owned" and "what if the code repository gets owned" etc. 但是,如果服务器仅是用于完全加密的数据的存储设施,并且客户端采用足够动态和复杂的方法来加密/解密该数据,则它倾向于帮助解决“如果服务器拥有所有权”和“如果拥有服务器”的问题。代码存储库被拥有”等

Now if there are any major flaws in the above approach then of course, I would love to hear that so it can be improved. 现在,如果上述方法中有任何重大缺陷,那么,我当然希望听到可以改进的地方。


I just ended up taking two keypairs. 我刚刚结束了两个密钥对。 One of them I used to encrypt the other one. 我曾经加密其中一个。 Then I broke up the encrypted form into many shards and stashed them all over the place... in the cloud... on servers... in obfuscated strings on my app... etc. 然后,我将加密形式分解为许多碎片,并将它们散布在各处……在云中……在服务器上……在我的应用程序中的混淆字符串中……等等。

None of the strings involved in the encryption or keys is in string or binary format in the compiled app. 在编译的应用程序中,加密或密钥中涉及的所有字符串都不是字符串或二进制格式。 It is all generated programatically in a quite obfuscated fashion. 所有这些都是以非常模糊的方式通过程序生成的。

At runtime we use arcane math functions to build method names that call hidden methods around the app to assemble the first key, then we go get the encrypted shards of the second key from all over the internet and decrypt them with the first key, then we use the second key to decrypt the important client data. 在运行时,我们使用神秘的数学函数来构建方法名称,该名称将在应用程序周围调用隐藏方法以组装第一个密钥,然后我们从Internet上获取第二个密钥的加密碎片,并使用第一个密钥对其进行解密,然后使用第二个密钥解密重要的客户端数据。

Then we use a special sauce method where none of the code that's involved in this obfuscation is anywhere in our repository. 然后,我们使用一种特殊的调味方法,这种混淆处理所涉及的代码都不在我们的存储库中。 It gets loaded in dynamically at a special time. 它会在特定时间动态加载。 :D That's all I will say about that. :D这就是我要说的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM