【问题标题】:How to secure API (private key) for mobile apps如何保护移动应用程序的 API(私钥)
【发布时间】:2013-12-26 16:26:43
【问题描述】:

我正在构建一个只能供 iOS 应用访问的 Web 服务。 将来我想扩展到移动网站,使我的服务也可用于其他移动操作系统。

现在,我通过 API 完成了所有工作。我的用户可以注册、搜索公司、从这些公司订购产品并跟踪他们的订单。它还没有激活,但它正在工作..

我面临一个主要问题:如何确保这一点?

在过去的几天里,我停止了编码,并且一直忙于在网络、StackOverflow 和信息安全中搜索如何做到这一点。我发现亚马逊保护他们的 API 的方式对我来说是最好的解决方案。 here 解释了亚马逊保护其服务的方式。我为我的服务做了一些调整:

  1. 用户注册并获取私有 API 密钥 + 公共(识别)密钥
  2. 用户输入凭据并点击“登录”。应用程序使用变量 + 私钥创建散列。应用向 API 发送变量 + 时间戳 + 哈希 + 公钥
  3. API 在数据库中查找公钥,找到属于该公钥的私钥(如果公钥有效)。然后,API 以与应用程序相同的方式创建哈希。如果哈希值相同,则执行请求(在本例中为登录)。

这种保护服务的方式对我来说很有意义,而且我可以编写大部分代码。但我有一个大问题,我找不到任何解决方案:

  • 创建帐户时,用户会获得一个公共和私有 API 密钥。公钥可以从服务器发送到用户设备,因为这不一定是秘密。由于私有 API 密钥永远可以通过网络发送,我到底如何才能确保在用户设备上登录的帐户知道私有 API在服务器上创建的密钥?

有人知道如何解决这个问题吗?任何帮助将不胜感激!

【问题讨论】:

    标签: ios web-services api security key


    【解决方案1】:

    我认为您的身份验证方案过于复杂。 我建议使用像 oauth2 这样广泛使用的协议来保护您的 API - http://oauth.net/2/
    有很多客户端库和服务器端插件支持和实现它,并且可以轻松集成到您的应用程序中。

    【讨论】:

    • 感谢您的回复,我会看看这个!
    【解决方案2】:

    这是我解决相同问题的方法以及为什么我认为您的实际问题与您认为的不同:

    Amazon 的做法是有意义的、安全的,并且比 oAuth 更容易实施,所以我不确定为什么每个人都建议使用它。我使用亚马逊的方法是这样的:

    1. 用户注册以使用 API。我们确保生成公钥、密钥,并保存联系人电子邮件、角色(我们的角色是“管理员”和“用户”),然后将 API 用户的status 设置为活动状态。这允许我们在服务器上管理基于角色的权限(速率限制、访问控制等)并随时停用帐户
    2. 我们将客户端 ID 和密钥发送回客户端。没有办法解决这个问题,因此您可以通过以下方式使其尽可能安全:
      • 只发送一次令牌。如果用户忘记了他们的令牌,他们需要注册一个新的 API 客户端
      • 确保所有请求都通过 HTTPS 发出,没有例外 - 这样可以加密任何嗅探到的流量,攻击者只有一次拦截机会
      • 加密数据库中的令牌。不要散列它,因为它需要是可逆的。如果您在使用 AES-256 加密时安全地存储您的加密密钥并生成一个新的随机 IV(初始化向量),那么攻击者将无法检索客户端密钥(理论上,如果您正确保护该密钥,但即使不是它为您争取一些时间来停用受损的客户端令牌)。您在生成纯文本令牌时将其发送给客户端,但在它到达数据库之前对其进行加密。
    3. 当客户端发出请求时,它们会发送标头和签名请求。在您的服务器上,您可以找到与客户端 ID 关联的加密令牌,对其进行解密,然后计算签名并将其与发送的内容进行比较。如果您计算出的签名与其匹配,那么您让请求继续进行。

    就像我说的那样,没有办法将私有令牌发送给客户端,但好处是您只需执行一次,而且无论如何都应该通过 SSL。

    您缺少的问题是如何在设备本身上保护该令牌。这是我还没有看到任何解决方案的另一个问题。

    这两种情况唯一可行的选择是:

    1. 您在服务器上为每个客户端生成一次私有令牌,并且只将其发送给客户端一次(没有提醒,只有像 Amazon 那样的总重置)
    2. 除了将令牌存储在设备本身之外,您真的无能为力。

    我们为保护设备上的令牌而提出的一项措施是定期轮换令牌。例如,您将令牌存储在每个用户的设备上或硬编码到应用程序中。每隔一段时间,您就需要设备的新令牌。如果您有硬编码令牌,那么您使用新的硬编码令牌更新应用程序,当用户通过他们的应用商店更新时,他们将自动获得新令牌。然后,您撤销所有 X 天前的令牌,并要求任何落后者更新应用程序。如果每个客户端在登录/注册时都获得一个唯一令牌,则另一个选项是也使该令牌过期,然后在他们下次使用该应用程序时自动将其注销。重新登录后,您会生成并发送一个有效期为 X 天的新令牌。

    最后,这些是一些常见的问题,我认为至少对于您使用的身份验证方法来说还没有解决。因此,您真正能做的最好的事情就是接受与发送和存储令牌相关的小风险,并投入精力使 API 安全。

    【讨论】:

    • 在您的第二句话中,您质疑 OAuth 的使用,然后您发现唯一的问题是如何保护设备本身上的令牌,而 OAuth 作为解决方案。
    【解决方案3】:

    正如 Rotem Hermon 建议的那样,我也会实施 Oauth2。

    关于“我到底如何确保在用户设备上登录的帐户知道在服务器上创建的私有 API 密钥?”问题,(在非常抽象的层面上)服务器通过私钥的签名计算确认客户端知道私钥。

    一个愚蠢的抽象例子:

    服务器拥有私人客户密钥(“Z”) 客户有他的私钥(“Z”)

    他们都知道他们的公钥(“Y”)

    客户端对资源(“A”)的请求和他的私钥和公钥进行哈希处理,以使用类似 signMyRequest(request,publicKey,privateKey) 的函数对请求进行签名

    在这个例子中是signMyRequest("A","Y","Z")

    公钥将符合“用户名”的角色,而私钥将符合“密码”的角色。不同之处在于您不将其传递给服务器,AWS 只是对私钥进行计算。查找 AWS Signature V4 以获取更多信息: http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

    希望对您有所帮助,并将其仅作为功能的抽象示例。

    除了身份验证和授权之外,您还应该关注常见的安全漏洞,例如 SQL 注入、XSS 等,因为它也是一个 Web 应用程序,并且大多数常见的安全漏洞都适用。

    【讨论】:

    • 您好,Igarr,感谢您的回复!我想我错误地提出了我的问题。您假设服务器端和客户端都已经知道密钥。我的意思是:创建帐户后,API 应该生成一个私钥并将该密钥与我的帐户一起存储在我的数据库中。但此时客户端还不知道私钥。如何确保客户端知道存储在数据库中的私钥,而不是通过网络发送?
    • 哦,我的错。那么你也必须以某种方式发送它。甚至 Amazon Web Services 通过使用 SSL 的安全通道通过他的网站至少发送一次。如果您想避免这种情况,您可以实施 RSA 令牌解决方案(安全但昂贵),让用户设置他的私钥(不安全但易于实施)或使用电子邮件或 SMS 等其他渠道发送。
    • 啊,所以私钥永远不应该发送到任何地方的规则并不那么严格......谢谢!我也会研究 Oauth2 ;)
    • 不应该在每笔交易中都发送,它必须至少发送一次。我想我会通过另一种方式发送私钥来选择最后一个选项,这是一般建议,所以如果有人入侵开发人员帐户,它也不会拥有他的私钥。但我认为 oauth2 在这种情况下会让你节省很多时间和精力:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 2016-03-04
    • 2020-06-18
    • 2015-12-29
    • 1970-01-01
    • 2020-09-13
    相关资源
    最近更新 更多