API 机密可以以纯文本形式存储或可解密吗?

信息安全 Web应用程序 密码 验证 网络服务 贮存
2021-09-07 18:06:33

API keys考虑用户名和API secrets密码吗?为什么像 Amazon Web Services 这样的 API 服务器允许您以纯文本形式查看 API 密码?这让我觉得他们以纯文本或至少以可解密的格式存储它。

如果 API 机密被视为您应该输入以创建然后在数据库中散列而不是以纯文本形式交给您的密码,这不是更好吗?如果由于某种原因,他们的 API 秘密数据库遭到破坏,它将很容易为许多使用其 API 的应用程序打开闸门。但是,如果它以不可解密的方式进行散列,那么所有内容都不会轻易丢失。

4个回答

不可以。API 密钥需要以明文形式存储。

它们不是密码:它们是加密密钥。这些密钥用于验证请求(使用 SHA1-HMAC)之类的事情。服务器需要知道加密密钥才能应用加密算法。

因此,API 密钥需要以明文形式存储在服务器上。如果服务器仅存储 API 密钥的哈希,则无法验证来自客户端的消息的真实性或验证发送给客户端的消息。

这里和其他地方似乎有些混乱,所以我添加了这个答案,希望它能为其他用户澄清情况。

可以使用两种类型的 API 机密。

此页面上的大多数答案都在讨论的用例是密钥,用于使用 HMAC 等算法对消息进行签名和验证。在这种情况下,客户端和 API 都需要密钥的实际值来创建消息的签名。然后,服务器将其生成的签名与客户端发送的签名进行比较,并能够验证消息。如上所述,如果原始密钥在服务器上不可复制,则无法正常工作。在最初与客户端共享密钥(通过加密通道)之后,密钥不再需要在客户端和服务器之间传输。

另一个常见的 API 客户端机密只是机密凭证(您可能会在典型的 OAuth2 访问令牌请求中看到)。此凭据在每个请求上传输,因此只能通过加密通道(例如 HTTPS)传输。在这种情况下,服务器只需要保留足够的信息来验证客户端提供的秘密值是否正确,因此可以并且应该对秘密进行哈希处理。在这种情况下,秘密实际上充当了密码,因此应采取相同的预防措施。

免责声明:我不是安全研究人员,在盲目遵循 StackExchange 上的任何建议之前,您绝对应该对此和任何主题进行更多研究。

tl;dr最重要的一点是不同的 API 可能以不同的方式使用秘密。为了评估存储它的最佳实践,了解您的 API 如何使用客户端密码非常重要。

散列不是存储;它会不可逆转地破坏数据。我们可以将密码散列称为“密码存储”,因为当我们真正需要密码时,我们有一个方便的人工操作员来输入它。事实上,当我们散列密码时,我们不存储密码,而只是一个令牌足以验证输入的密码。

API 密钥的存储方式必须能够以无人值守的方式再次使用。服务器必须真正存储它,而不是只记住它的影子,因为它需要真正的密钥才能访问 API。

虽然对 API 令牌进行散列会更安全,但它会带来一个可用性问题:令牌是长且随机的,并且在散列之前只需要告诉用户一次。这使得用哈希保护它们有点困难。

我对安全方案的建议如下:

  1. 生成一个随机salt值并将其存储在数据库中。这个盐不能等于用户的密码盐。
  2. 获取用户的明文密码并计算KDF(password, salt),其中KDF是密钥派生函数,例如 bcrypt。调用结果值k
  3. 生成 API 密钥。
  4. 使用 AES 加密 API 密钥值,k用作密钥,并将密文存储在数据库中。
  5. 丢弃明文 API 密钥和k.

当用户登录时,webapp 知道他们的密码并使用它来计算k,然后用于解密 API 密钥并将其显示给他们。

当用户希望使用 API 时,他们必须k通过 SSL 发送明文 API 密钥。然后,webapp 可以使用给定的 API 密钥解密存储的 API 密钥值k并将其与给定的 API 密钥进行比较。如果它们匹配,则它是有效的。这允许在应用程序无需存储用户密码的情况下使用 API 密钥。

如果攻击者破坏了数据库,他们必须破解用户密码才能计算k.