如何保护移动应用的API(私钥)

时间:2013-12-09 14:11:38

标签: ios web-services api security key

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

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

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

在过去的几天里,我已停止编码,而且我一直忙于搜索网络,StackOverflow和信息安全,以了解如何执行此操作。我发现亚马逊获取API的方式对我来说是最好的解决方案。亚马逊确保其服务的方式解释为here。我已经为我的服务稍微调整了一下:

  1. 用户注册并获取私有API密钥+公共(标识)密钥
  2. 用户输入凭据并点击“登录”。应用程序从变量+私钥创建哈希。应用程序将变量+时间戳+哈希+公钥发送到API
  3. API查找数据库中的公钥,查找属于该公钥的私钥(如果公钥有效)。然后API以与应用程序相同的方式创建哈希。如果哈希值相同,则执行请求(在本例中为登录)。
  4. 这种保护服务的方式对我来说很有意义,我可以编写大部分代码。但我遇到了一个重大问题,我找不到任何解决办法:

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

    有谁知道如何解决这个问题?任何帮助将非常感谢!!

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

以下是我如何解决同样的问题以及为什么我认为您的实际问题与您认为的问题不同:

亚马逊的做法有道理,安全,并且比oAuth更容易实现,因此我不确定为什么每个人都建议使用它。我使用亚马逊方法,如下所示:

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

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

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

    1. 您在服务器上为每个客户端生成一次私有令牌,并且只将其一次性发送到客户端(没有提醒,只有像亚马逊一样重置)
    2. 除了将令牌存储在设备本身之外,你真的无能为力。
    3. 我们提出的用于在设备上保护令牌的一个措施是实际上定期旋转令牌。因此,例如,您可以将令牌存储在设备上,供每个用户使用,也可以硬编码到应用程序中。您经常需要为设备添加新令牌。如果您有一个硬编码令牌,那么您使用新的硬编码令牌更新应用程序,当用户通过他们的应用商店更新时,他们将自动获得新令牌。然后撤销所有X天的令牌并要求任何落后者更新应用程序。如果每个客户端在登录/注册时被赋予唯一令牌,则另一个选项是使令牌失效,然后在下次使用应用程序时自动将其注销。重新登录后,您将生成并发送一个有效期为X天的新令牌。

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

答案 2 :(得分:1)

正如Rotem Hermon建议我也会实施Oauth2。

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

一个愚蠢的抽象例子:

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

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

客户端将请求散列到资源(“A”)及其私钥和公钥,以使用此函数signMyRequest(request,publicKey,privateKey)

对此请求进行签名

在此示例中为signMyRequest("A","Y","Z")

Public Key将遵守'username'的角色,私钥将符合'password'的作用。不同之处在于您不将其传递给服务器,AWS只是对私钥进行计算。查找AWS Signature V4以获取更多信息: http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html

希望有助于将其作为功能的抽象示例。

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