在iOS中,我该如何存储一个秘密的“key”,以便我能够与我的服务器进行通信?

37

我想存储一个秘密密钥("abc123"),并在我的REST API请求头中使用它。我的服务器将检查这个秘密密钥。如果与"abc123"匹配,则允许请求。

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

let secret = "abc123" 

但是这会有什么不利之处吗?


https://dev59.com/hZzha4cB1Zd3GeqPBje1#40423579 - Alexander
你使用了“secret key”这个词,但如果你是在头部发送,那么你实际上指的是api-key而不是secret-key。你能编辑一下你的问题吗? - mfaani
5个回答

31

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

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

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

实现这个功能的付出超过一个小时可能不值得。如果您想了解更多相关内容,请参阅 iPhone应用程序到网页的安全https加密及其链接。


Cocoapods-keys怎么样?它还是可以被破解的吗?你能给我展示一下如何在Swift中创建原始值字符串的例子吗? - TIMEX
3
我认为cocoapods-keys没有太多的混淆优势。它过于简单且可以自动恢复。混淆唯一的好处是保密性(这也是它通常如此薄弱的原因)。如果你开源了混淆,那么除了希望之外,你就没有别的了。 - Rob Napier
1
通过原始字节,我只是指一个简单的C字节数组。至少它不会从“字符串”中弹出。 - Rob Napier
这种方式有什么优势,不如什么都不做呢?这不就跟拥有一个难以猜测的URL一样吗?正确的密钥难道不应该至少在每个请求中有所不同吗? - pete
如果您通过HTTPS连接到服务器,则难以猜测的URL与此解决方案相同,因为URL以相同方式加密标头。我不知道您所说的“从请求到请求是否不同”,但如果您的意思是每个端点URL中可以嵌入一些不同的密钥,那么是的,这可能比这一方法略好一些。(记住我们谈论的是“几乎无用”和“几乎无用但稍微好一些”的区别)。 - Rob Napier
显示剩余5条评论

6
通过在应用程序中硬编码字符串,攻击者可以轻松解密您的二进制文件(使用dumpdecrypt等工具),并获得您的字符串(简单的十六进制转储将包括应用程序中的所有字符串)。
有一些解决方法。您可以在REST API上实现一个端点,返回您的凭据,然后在启动时调用它。当然,这有其自身的非微不足道的安全问题,并需要额外的HTTP调用。我通常不会这样做。
另一种选择是以某种方式混淆秘密密钥。通过这样做,攻击者将无法在解密后立即识别您的密钥。cocoapods-keys是使用此方法的一种选项。
这里没有完美的解决方案-您能做的最好的事情就是尽可能地使攻击者难以获取到您的密钥。
(另外,请确保在发送请求时使用HTTPS,否则这是破坏您的密钥的另一种好方法。)

通过在应用程序中硬编码字符串,攻击者可以解密您的二进制文件。这只会发生在越狱的iOS设备上,对吗? - aguilarpgc
@aguilarpgc 不需要,你可以从任何iOS设备上获取二进制文件。 - Tres

2
虽然内部令牌通常用于某些方案,但您可能最终会实现TLS以保护网络流量和令牌。在另一个回复中,Rob Napier提到:这里
在此处使用自己的证书链可允许使用现有的TLS安全和身份验证机制以及iOS密钥链,并为您提供吊销TLS凭据的选项(如果(何时?)需要),并允许客户端将其连接固定到您的服务器并检测服务器欺骗(如果需要)。
您自己的证书颁发机构和证书链是免费的,并且一旦将根证书加载到客户端中,您自己的证书与商业购买的证书一样安全。
简而言之,这种基于证书的方法结合了加密和身份验证,使用现有的TLS机制。

请解释一下:“一旦您将根证书加载到客户端”。您是指只加载到应用程序中,还是加载到iOS CA列表中,或者其他什么地方? - zaph
1
我相信Stephen正在描述一种证书固定的形式,因此只有您的应用程序需要您的根证书,并且您的应用程序仅信任您的根证书。 - Rob Napier
1
在任何时刻,服务器都假定应用程序是可信的,可以接收机密信息,并且没有实际验证应用程序身份的方式 - 它可能是被黑客克隆的。您需要使用应用程序秘密来交付您的应用程序。或者由操作系统为您的应用程序生成的应用程序秘密,并使用操作系统范围的密钥签名以证明生成的密钥。但这将需要操作系统在每个设备上拥有一个秘密密钥。因此,同样的问题:以防篡改的方式在客户端存储密钥。有专门的硬件可以做到这一点,但并未在每个设备上采用。 - Radu Simionescu

0

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

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

    }

0

看起来你正在使用访问令牌。我建议使用Keychain存储访问令牌。对于客户端ID,我建议将其保留为变量,因为客户端ID不会更改,而访问令牌会随用户或刷新令牌而更改,而Keychain是存储用户凭据的安全位置。


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