Google、Stripe 和许多其他公司都有公共 API 密钥和秘密 API 密钥。
生成随机字符串很容易,但我的问题是,如何生成公钥和私钥、存储它们并正确使用它们?
公共 API 密钥用于告知用户是谁,秘密用于确认用户的身份。
我的流程如下:
- 用户创建帐户
- 用户激活服务(内部)
- 服务返回公共和秘密 API 密钥(UARRHAtPtJcLxx5RmMWo9oTrca4gRt2k、C9YS7Mhzichq2vqBuRkNJxkNci5W2Xua)
- 用户在他/她的网站上使用公钥,在服务器端使用私钥
我使用的是nodejs,当用户请求API密钥时,公钥是按需生成的:
let public = await crypto.randomBytes(32).toString('base64');
将秘密存储在数据库中就像以明文存储密码一样。
我想我们不想要这个,它需要以某种方式进行散列。例如,我是否生成一个“私钥”并使用 argon2 对其进行哈希处理?用户将永远无法再次看到他/她的密钥,并且需要立即保存它,这是一个好的做法吗?
我找不到太多关于这应该如何工作的信息。
从技术上讲,您所指的只是用户名和密码。唯一重要的区别是这些通常由 API 生成并且非常随机,而不是由用户选择的真实用户名和密码,并且通常不是非常随机。 (调用这些公钥和私钥有点误导,因为公钥加密是不同的 - 通常不需要 API 密钥,管理 PKI 很麻烦,而且正确执行的成本也非常高。)
由于这些在技术上与用户名和密码相同,因此您希望以类似的方式对待它们。我们将这些称为客户端 ID(“公共”部分)和客户端密钥(“秘密”部分)。
一些想法:
- 您应该使用加密安全的随机生成器来生成随机字符串。
crypto.randomBytes()
如上所述就可以了。
- 您应该考虑熵来为密钥设置适当的长度。熵基本上是密钥的“随机性”,以位为单位进行测量。举个例子,如果密钥空间是 1024 个具有相同概率的不同可能密钥,那么您可以说该密钥具有 log2(1024) = 10 位熵。熵将密钥的长度与随机源的安全性解耦,例如,您可以拥有很长的密钥,但仍然不安全,因为随机源有缺陷。您想要的密钥有多少熵取决于用例,例如在任何情况下都可能进行离线攻击,或者仅在线请求等等(您也应该考虑离线攻击,这些攻击是very快速地)。根据经验,熵不应低于 128 位,为了获得更高的安全性,您可能应该使用 256 位以上。如果密钥区分大小写和字母数字,则有 62 个不同的可能字符,22 的密钥长度提供约 131 位(
log2(62^22) =~ 130.99
)。当然,您总是可以更长,对于 256 位,您需要 43 的长度,并且区分大小写的字母数字。
- 正如您正确指出的那样,存储此类密钥至关重要。至少,您希望将它们存储为散列(使用适当的散列,见下文),就像任何其他密码一样,这样即使攻击者获得了对您数据库的访问权限,他们也不会看到您的 api 密钥。任何适当的密钥派生函数(Argon2、bcrypt、PBKDF2 等)都适合此目的,但普通加密哈希函数(sha1、sha2 等)是not.
- 你是对的,如果你对这些秘密进行哈希处理,用户将只能在生成它们时才能看到它们,而再也不会看到它们。这正是安全在线服务中发生的情况,并且通常是一个很好的做法。您可以警告用户记下该秘密,因为您将无法再次向他们显示。 (此外,如果他们忘记了,他们最好可以生成一个新的,所以这通常不是什么大问题。)
- 更好的办法是将这些密钥存储在其他地方。考虑到云,存储此类机密的好地方是云提供商提供的服务,例如 AWS 中的 Secrets Manager。好处包括使用 KMS 密钥进行加密、审核,并且您可以确保访问密钥的唯一方法是通过适当的 IAM 角色(例如,您无需担心泄露备份等问题)。
- 虽然客户端 ID 不是秘密,但您需要在存储中保护其完整性(以及与客户端秘密关联的完整性)。想象一个场景,攻击者可以以某种方式更改您的数据库,并将不同的(攻击者已知的)客户端密钥分配给现有的客户端 ID。这意味着与该客户端 ID 相关的数据将被完全泄露。因此,您要确保除了保证客户端秘密的安全外,攻击者也不可能更改这些秘密(例如通过对所涉及组件的访问控制)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)