服务如何生成和使用公共和秘密 API 密钥? [英] How services generate and use public and secret API keys?

查看:21
本文介绍了服务如何生成和使用公共和秘密 API 密钥?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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 位熵.熵将密钥的长度与随机源的安全性分离,例如,您可以拥有仍然不安全的非常长的密钥,因为随机源存在缺陷.您希望密钥有多少熵取决于用例,例如在任何情况下是否可能进行离线攻击或仅在线请求等等(您可能也应该计算离线攻击,它们非常).根据经验,您不应低于 128 位的熵,为了更高的安全性,您可能应该使用 256+ 位.如果密钥区分大小写和字母数字,则有 62 个不同的可能字符,密钥长度为 22 提供 ~131 位(log2(62^22) =~130.99).当然,您总是可以使用更长的时间,对于 256 位,您需要长度为 43 且区分大小写的字母数字.
  • 正如您正确指出的,存储此类密钥至关重要.至少,您希望将它们散列存储(使用适当的散列,见下文),就像任何其他密码一样,这样即使攻击者获得了对您数据库的访问权限,他们也不会看到您的 api 密钥.任何适当的密钥派生函数(Argon2、bcrypt、PBKDF2 等)都适用于此目的,但普通的加密哈希函数(sha1、sha2 等)不是.
  • 你是对的,如果你散列这些秘密,用户将只能在它们生成时才能看到它们,再也不会看到它们.这正是安全在线服务中发生的情况,通常是一种很好的做法.您可以警告您的用户记下该机密,因为您将无法再次向他们显示.(此外,如果他们忘记了,他们可以理想地生成一个新的,所以这通常没什么大不了的.)
  • 最好将这些密钥存储在其他地方.考虑到云,此类秘密的好地方是您的云提供商提供的服务,例如 AWS 中的 Secrets Manager.好处包括使用 KMS 密钥进行加密、审核,并且您可以确保访问密钥的唯一方法是通过适当的 IAM 角色(例如,您无需担心泄露备份之类的事情).
  • 虽然客户端 ID 不是机密,但您需要在存储中保护其完整性(以及与客户端机密关联的完整性).想象一个场景,攻击者可以以某种方式更改您的数据库并将不同的(攻击者已知的)客户端密钥分配给现有客户端 ID.这将意味着与该客户端 ID 相关的数据完全泄露.因此,您要确保除了保持客户端机密安全外,攻击者也无法更改这些内容(例如通过对相关组件的访问控制).

Google, Stripe and many other companies have public API key and Secret API key.

It is easy to generate random strings but my question is, how can I generate public and secret keys, store them and use them properly?

The public API key is to tell who the user is and the secret is to confirm their identity.

My flow is as follow: - User create an account - User activates a service (in-house) - The service return a public and a secret API key (UARRHAtPtJcLxx5RmMWo9oTrca4gRt2k, C9YS7Mhzichq2vqBuRkNJxkNci5W2Xua) - User use the public key on his/her website and the private key on the server-side

I am using nodejs and the public key is generated on demand, when the user asks for an API key:

let public = await crypto.randomBytes(32).toString('base64');

Storing the secret in a database would be like storing password in plaintext. I presume we do not want this and it needs to be hashed somehow. Do I generate a "private" key and hash it using argon2 for example? The user will never be able to see his/her key again and will need to save it right away, is this good practice?

I couldn't find much information on how this is suppose to work.

解决方案

Technically what you are referring to are just a username and a password. The only important difference is these are typically generated by the API and very random, as opposed to a real username and password which are chosen by a user, and usually not very random. (Calling these public and private keys is a little misleading as public key cryptography is different - you don't typically need that for API keys, managing a PKI is a can of worms, and also very costly to do it properly.)

As these are technically the same as a username and a password, you want to treat them similarly. Let's call these client id (the "public" part) and client key (the "secret" part).

A few thoughts:

  • You should use a cryptographically secure random generator to generate random strings. crypto.randomBytes() as above is fine.
  • You should consider entropy to set an appropriate length for the key. Entropy is basically the "randomness" of your keys, and is measured in bits. Just for an example, if the key space is say 1024 different possible keys with equal probabilities, then you can say the key has log2(1024) = 10 bits of entropy. Entropy decouples the length of the key from the security of the random source, for example you can have very long keys which are still not secure, because the random source is flawed. How much entropy you want for your keys depends on the usecase, like if offline attacks are possible in any scenario or online requests only and so on (you should likely count with offline attacks too, which are very fast). As a rule of thumb, you should not go below 128 bits of entropy, and for higher security you should probably go 256+ bits. If the key is case sensitive and alphanumeric, then there are 62 different possible characters, a key length of 22 provides ~131 bits (log2(62^22) =~ 130.99). You can always go longer of course, for 256 bits you would need a length of 43 with case sensitive alphanumeric.
  • As you correctly noted, storing such keys is critical. At the very least, you would want to store them hashed (with an appropriate hash, see below), just like any other password, so that even if an attacker gains access to your database, they won't get to see your api keys. Any proper key derivation function (Argon2, bcrypt, PBKDF2 and so on) is fit for this purpose, but plain crypto hash functions (sha1, sha2 and so on) are not.
  • You are right that if you hash these secrets, the user will only be able to see them when they are generated and never again. That's exactly what happens in secure online services, and is generally a good practice. You can warn your user to take note of the secret because you will not be able to show them again. (Also they can ideally generate a new one if they forgot it, so it's usually not a big deal.)
  • Even better would be to store these keys somewhere else. Thinking about cloud, a good place for such secrets would be a service provided by your cloud provider, like for example Secrets Manager in AWS. The benefits include encryption with a KMS key, auditing, and you can make sure that the only way to access your keys is through appropriate IAM roles (you don't need to worry about things like a disclosed backup for example).
  • While the client id is not a secret, you need to protect its integrity (and the integrity of the association with a client secret) in your storage. Imagine a scenario where an attacker can somehow alter your database and assign a different (attacker-known) client secret to an existing client id. That would mean a total compromise of data associated with that client id. So you want to make sure that besides keeping the clietn secret secure, it is also not possible for an attacker to change those (via for example access control to components involved).

这篇关于服务如何生成和使用公共和秘密 API 密钥?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆