在 iOS 中,如何存储允许我与服务器通信的秘密“密钥”?

Posted

技术标签:

【中文标题】在 iOS 中,如何存储允许我与服务器通信的秘密“密钥”?【英文标题】:In iOS, how can I store a secret "key" that will allow me to communicate with my server? 【发布时间】:2015-06-27 21:45:09 【问题描述】:

我想存储一个密钥(“abc123”),我将在 REST API 请求的标头中使用它。我的服务器将检查此密钥。如果匹配“abc123”,则允许发出请求。

我正在考虑一个简单的解决方案,例如:

let secret = "abc123" 

但是这会有什么缺点吗?

【问题讨论】:

***.com/a/40423579/3141234 您确实使用了密钥一词,但如果您在标头中发送,那么您的意思实际上是api-key 而不是secret-key。你能编辑你的问题吗? 【参考方案1】:

听起来很疯狂,这可能是最好的解决方案。其他一切都更复杂,但并不安全。您使用的任何花哨的混淆技术都将被逆向工程几乎与他们找到此密钥一样快。但是这种静态密钥解决方案虽然非常不安全,但几乎与其他解决方案一样安全,同时几乎没有增加额外的复杂性。我喜欢它。

它几乎会立即被破坏,但所有其他解决方案也将如此。所以保持简单。

您真正想做的一件事是使用 HTTPS 和pin your certificates。我会选择一个长的、随机的、不是单词的密钥。理想情况下,它应该是一个完全随机的字节串,存储为原始值(而不是字符),这样它在二进制文件中就不会那么明显了。如果您想发疯,请在发送之前对其应用 SHA256(因此实际密钥永远不会出现在您的二进制文件中)。同样,这很容易破解,但很容易,并且不会浪费大量时间进行开发。

任何超过一个小时的努力都不太可能值得费心来实现此功能。如果您想了解更多关于该主题的信息,请参阅Secure https encryption for iPhone app to webpage 及其链接。

【讨论】:

cocoapods-keys 怎么样?那还可以破吗?你能告诉我一个如何在 swift 中创建原始值字符串的例子吗? 我没有看到 cocoapods-keys 的混淆优势。它太简单了,而且自动可逆。唯一的混淆就是保密(这就是为什么它经常如此脆弱)。如果你开源你的默默无闻,除了希望,你别无所求。 原始字节是指一个简单的 C 字节数组。至少它不会从“字符串”中弹出。 这比什么都不做更好?这和只有一个难以猜测的网址一样吗?正确的密钥不应该至少因请求而异吗? 如果您通过 HTTPS 连接到您的服务器,那么难以猜测的 URL 与此解决方案相同,因为 URL 的加密方式与标头相同。我不知道您所说的“因请求而异”是什么意思,但如果您的意思是可以在每个端点 URL 中嵌入一些不同的密钥,那么是的,这可能是比这个更好的解决方案。 (请记住,我们谈论的是“几乎没用”和“几乎没用但稍微没用”之间的区别。)【参考方案2】:

通过在您的应用程序中对字符串进行硬编码,攻击者可以解密您的二进制文件(通过dumpdecrypt 等工具)并轻松获取您的字符串(一个简单的 hexdump 将包含您应用程序中的任何字符串)。

有一些解决方法。您可以在 REST API 上实现一个端点,该端点返回您的凭据,然后您可以在启动时调用该端点。当然,这有其自身重要的安全问题,并且需要额外的 HTTP 调用。我通常不会这样做。

另一种选择是以某种方式混淆密钥。通过这样做,攻击者将无法在解密后立即识别您的密钥。 cocoapods-keys 是使用这种方法的一个选项。

这里没有完美的解决方案 - 您能做的最好的事情就是让攻击者尽可能难以获得您的密钥。

(另外,发送请求时请务必使用 HTTPS,否则这是破坏密钥的另一种好方法。)

【讨论】:

By hardcoding the string in your app, it's possible for attackers to decrypt your binary 这只能发生在有根的 ios 设备上,对吧? @aguilarpgc 不,您可以从任何 iOS 设备获取二进制文件。【参考方案3】:

虽然带内令牌通常用于某些方案,但您最终可能会实施 TLS 来保护网络流量和令牌。 This as Rob Napier mentions in another reply.

在此处使用您自己的证书链允许使用现有的 TLS 安全和身份验证机制以及 iOS 钥匙串,如果(何时?)有必要,您还可以选择撤销 TLS 凭据,还允许客户端锁定它与您的服务器的连接并在必要时检测服务器欺骗。

您自己的证书颁发机构和您自己的证书链是免费的,而且您自己的证书——一旦你将根证书加载到客户端——与商业购买的证书一样安全。

简而言之,这种基于证书的方法结合了加密和身份验证,使用现有的 TLS 机制。

【讨论】:

请解释:“一旦您将根证书加载到客户端”。您是指进入应用程序、进入 iOS CA 列表还是其他什么? 我相信 Stephen 是在描述一种证书固定的形式,所以只有你的应用需要你的根证书,而你的应用只信任你的根证书。 在任何时候,服务器都假设应用程序可以接收秘密信息,并且它没有验证应用程序身份的实际方法 - 它可能是被黑客入侵的克隆。您需要随您的应用程序提供应用程序机密。或者由操作系统为您的应用程序生成的应用程序机密,并使用操作系统范围的密钥签名以证明生成的密钥。但这将要求操作系统在每个设备中都有一个密钥。所以同样的问题:以防篡改的方式将密钥存储在客户端。有专门的硬件,但尚未在每台设备上采用。【参考方案4】:

您似乎正在使用访问令牌。我会使用钥匙串作为访问令牌。对于客户端 ID,我会将它们保留为变量,因为客户端 ID 不会更改,而每个用户的访问令牌都会更改,甚至每个刷新令牌都会更改,并且钥匙串是存储用户凭据的安全位置。

【讨论】:

【参考方案5】:

我使用了 PFConfig 对象(一个字典),它允许您在应用程序中检索存储为服务器环境参数的变量值。 类似于可以在网站服务器端编程(如 Ruby 或 php)中使用 ENV 检索的环境变量。 在我看来,这与在 Ruby 或类似中使用环境变量一样安全。

PFConfig.getConfigInBackgroundWithBlock
      (config: PFConfig?, error: NSError?) -> Void in
      if error == nil 
        if let mySecret = config["mySecret"] as? String 
          // myFunction(mySecret)
        

    

【讨论】:

以上是关于在 iOS 中,如何存储允许我与服务器通信的秘密“密钥”?的主要内容,如果未能解决你的问题,请参考以下文章

在数据库中存储 API 密钥和秘密

我与小娜(03):量子超距通信,保持联系未来

如何在 S3 中存储数据并允许用户使用 rails API / iOS 客户端以安全的方式访问?

如何允许用户在 iOS 中使用 AFNetworking 信任和固定自签名 SSL 证书

Docker 服务之间是如何通信的呢?指定服务端口的背后隐藏了哪些秘密?带你揭秘 Docker 网络的神秘面纱!

Docker 服务之间是如何通信的呢?指定服务端口的背后隐藏了哪些秘密?带你揭秘 Docker 网络的神秘面纱!