保护 REST API:api_secret 签名和 ssl 是否足够?

信息安全 tls
2021-08-29 03:04:37

为了保护 RESTful API,我为每个调用考虑了以下身份验证过程:

  • 所有数据均经过 SSL 加密
  • 客户端发出的每个 HTTP 请求都会有一个签名,例如 sha512(keysort(POSTDATA.push({"secret": API_SECRET, "timestamp": utc_time()}))
  • 服务器也知道客户端 API_SECRET 并检查签名是否与客户端发送的签名匹配。如果是这种情况,则请求是合法的并将被处理。

我在这里面临的问题如下 - 由于 API 将由 iPhone 应用程序以及 WebApp 调用,我想不出一种传输 API_SECRET 一次的方法。因此,假设用户登录,发送 username=john&password=doe(SSL 加密)并从服务器接收到 API_SECRET 作为响应。然后,此 API_SECRET 将由客户端存储并用于签署所有进一步的 API 调用。

我正在使用签名来降低 MITM 攻击的风险,但是如果我在似乎有问题时转移密钥,但我想不出解决这个问题的方法。

谢谢你的帮助!

2个回答

您在这里问了两个不同的问题:关于在每个请求中生成“签名”的方法,以及关于API_SECRET在首次使用时向客户提供的方法。严格来说,这些应该分成两个问题,但我会回答两个问题。

您的签名格式。你有关于正确的基本概念,但我有一些建设性的建议/批评:

  • 使用 MAC。您应该使用消息身份验证代码,而不是哈希。正如您所做的那样,使用散列容易受到长度扩展攻击例如,您可以使用 MAC(K, D),其中 K 是您的API_SECRET,D 是请求的数据和时间戳,而 MAC 是安全消息验证码算法。AES-CMAC 是一个不错的 MAC 算法选择。SHA1-HMAC 是另一种标准选择。

  • 在请求中包含时间戳。您可能需要在请求中包含时间戳。服务器需要知道客户端使用的时间戳,以验证请求。由于您不能依赖客户端和服务器的时钟来完美同步,因此您需要在请求中发送时间戳。

  • 注意重复的参数。如果您有两个具有相同密钥的请求参数,那么您可能会遇到主机参数污染 (HPP) 攻击。我建议检查键是否都是唯一的,并且请求没有任何带有secret或键的参数timestamp(如果您要将这些参数添加到 POST 参数中)。

  • 谨防串联问题。您没有说如何获取已排序的参数列表并将它们转换为字符串。细节很重要。如果你只是连接所有的值,你将很容易受到攻击,因为字段之间的边界是不明确的。所以,不要使用连接;在准备数据以进行散列(或由 MAC 签名)时,使用一些明确的可解码编码。

  • 其他资源。另请参阅如何实现 API-Key-Mechanism以了解相关问题。

提供加密机密。因此,您需要一种方法来获取API_SECRET每个客户。这是一种标准的方法。首次登录时,用户将密码输入客户端。客户端打开到服务器的 SSL 连接并发送用户的用户名和密码。服务器验证用户的凭据,如果正确,则将此用户的API_SECRET值发送给客户端。客户端现在存储API_SECRET私有存储(但不存储用户密码)。在随后的连接中,客户端现在可以使用它API_SECRET来验证自己。

另一种方法。如果您打算仅从专用客户端(例如,移动应用程序、桌面应用程序;而不是从浏览器中运行的 Javascript)进行连接,那么您可以考虑以下替代方案。不要使用对称密钥加密,而是使用公钥加密。换句话说,不是使用 ,而是API_SECRET让每个客户端生成自己的 SSL 客户端证书。客户端安全地存储私钥。在第一次连接时,客户端使用用户的密码进行身份验证并发送它的公钥(实际上是它的证书),然后忘记用户的密码。服务器会记住客户端的证书,并且所有后续连接都通过使用带有客户端证书的 SSL 进行身份验证。

这是一个强有力的方法。它负责上面列出的所有潜在安全方法。唯一的缺点是您无法轻松编写在浏览器中运行的 Javascript/AJAX 客户端。

人力资源管理系统。在 SSL 之上,我不确定您从这里的 API_SECRET 中真正得到了什么。

我认为,假设您的客户端应用程序以值得信赖的方式分发,那么拥有来自已知、受信任来源的服务器 SSL 证书将是您可以做的最好的事情。此时,客户端可以通过 SSL 会话检查服务器的身份验证,服务器使用用户名/密码对客户端进行身份验证。

正如@Polynomial 所说 - SSL 应该加密会话,以便 SSL 端点之间的 MITM 攻击不是问题。诀窍是知道这些端点的位置,并确保它们位于您的基础设施中经过深思熟虑的位置。例如,如果在应用服务器前面有一个 SSL 端点 - 是什么保护了最后一英里的传输?

同样 - 应用程序(移动或网络)是否正确检查服务器的 SSL 证书是否来自受信任的来源?

在评论中添加问题:

我在 Mac 开发页面上查看了 NSURLReference 的类参考,根本找不到对 SSL 的任何参考……事实上,评论明确说它与协议无关,考虑到它被称为 URL 请求,这是有道理的。

我不认为你可以假设你甚至有这个类的 HTTPS - 你将不得不做一些事情来设置 HTTPS 会话而不是默认为 HTTP。这是关于 SSL 的 Mac 开发者概述这让我有点烦,因为没有明显的获取服务器证书的功能。

然后,您还需要证书、密钥和信任服务- 来验证证书。

我不会假设 Apple 开发环境会为您执行此操作。以前使用其他 API 的经验让我没有理由相信这一点,而且我没有看到明确说明它的作用的文档。我什至不确定信任存储在这个开发环境中是如何工作的。这不是你想做出盲目假设的地方。我会研究环境在什么条件下强制使用 SSL,验证服务器证书的真实性并验证证书是否由受信任的 CA 签名。如果您没有文档告诉您这些事情何时以及如何发生,您就不能真正假设您的服务是安全的。