生成新 API 密钥的最佳方法是什么?

问题描述 投票:0回答:8

所以现在有很多不同的服务,Google APIs, Twitter APIs, Facebook APIs, etc.

每个服务都有一个 API 密钥,例如:

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

所有密钥的长度和它们包含的字符都不同,我想知道生成 API 密钥的最佳方法是什么?

我不是在要求一种特定的语言,只是创建密钥的一般方法,它们应该是用户应用程序详细信息的加密,还是哈希,或随机字符串的哈希等。我们应该担心哈希吗算法(MSD、SHA1、bcrypt)等?

编辑: 我和几个朋友(电子邮件/推特)谈过,他们建议只使用去掉破折号的 GUID。

这对我来说似乎有点老套,希望能得到更多的想法。

security api-key
8个回答
83
投票

使用专为密码学设计的随机数生成器。然后 base-64 编码数字。

这是一个 C# 示例:

var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
    generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);

34
投票

API 密钥需要具有以下属性:

  • 唯一标识一个授权的API用户——“API密钥”的“密钥”部分
  • 验证该用户——无法猜测/伪造
  • 如果用户行为不当可以被撤销——通常他们输入一个可以删除记录的数据库。

通常您将拥有数千或数百万个 API 密钥,而不是数十亿个,因此他们不需要:

  • 可靠地存储有关 API 用户的信息,因为这些信息可以存储在您的数据库中。

因此,生成 API 密钥的一种方法是获取两条信息:

  1. 保证唯一性的序列号
  2. 足够的随机位来填充密钥

并使用私人秘密签名。

柜台保证他们唯一识别用户,签名防止伪造。可撤销性要求在执行任何需要 API 密钥授权的操作之前检查密钥在数据库中是否仍然有效。

如果您需要从多个数据中心生成密钥,或者没有其他好的分布式方式来分配序列号,那么一个好的 GUID 生成器是递增计数器的一个很好的近似值。


或随机字符串的散列

散列并不能防止伪造。 Signing 保证密钥来自您。


13
投票

更新,在Chrome的控制台和Node.js中,你可以发出:

crypto.randomUUID()

示例输出:

'4f9d5fe0-a964-4f11-af99-6c40de98af77'

原答案(更强):

您可以通过打开一个新选项卡,在 Chrome 上按 CTRL + SHIFT + i,然后输入以下立即调用的函数表达式 (IIFE) 来尝试您的 Web 浏览器控制台:

(async function (){
  let k = await window.crypto.subtle.generateKey(
    {name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
  const jwk = await crypto.subtle.exportKey("jwk", k)
  console.log(jwk.k)
})()

示例输出:

gv4Gp1OeZhF5eBNU7vDjDL-yqZ6vrCfdCzF7HGVMiCs

参考资料:

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey

https://developer.mozilla.org/zh-CN/docs/Web/API/SubtleCrypto/exportKey

我会承认我主要是为了自己写这篇文章以供将来参考...


8
投票

我使用 UUID,格式为小写,没有破折号。

生成很容易,因为大多数语言都内置了它。

API 密钥可能被泄露,在这种情况下,用户可能希望取消他们的 API 密钥并生成一个新密钥,因此您的密钥生成方法必须能够满足此要求。


7
投票

如果你想要一个只有字母数字字符的 API 密钥,你可以使用 base64-random 方法的变体,只使用 base-62 编码。 base-62编码器基于this.

public static string CreateApiKey()
{
    var bytes = new byte[256 / 8];
    using (var random = RandomNumberGenerator.Create())
        random.GetBytes(bytes);
    return ToBase62String(bytes);
}

static string ToBase62String(byte[] toConvert)
{
    const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    BigInteger dividend = new BigInteger(toConvert);
    var builder = new StringBuilder();
    while (dividend != 0) {
        dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
        builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
    }
    return builder.ToString();
}

1
投票

API 密钥应该是一些随机值。随机到无法预测。它不应包含它所针对的用户或帐户的任何详细信息。如果您确定创建的 ID 是随机的,那么使用 UUID 是个好主意。

Windows 的早期版本产生了可预测的 GUID,例如,但这是一个古老的故事。


0
投票

在终端中,您可以像这样使用

openssl

openssl rand -hex 32

示例输出:

1e846f3fcf103f64ca10fa4eac73bfae32ef10750bf4eae29132dc099526c561

0
投票

我喜欢 Chris Chiasson 在浏览器中

crypto.subtle
的使用,但想要一个命令行版本。如果你安装了 NodeJS,这可以保存在一个文件中(例如,
mkapikey.js
):

#!/usr/bin/env node
crypto.subtle.generateKey({name:"AES-GCM", length:256},true,
["encrypt","decrypt"]).then(key => {crypto.subtle.exportKey("jwk",key).
then(jwk => {console.log(jwk.k)})});

chmod +x
到可执行文件或使用
node mkapikey.js
调用。

chmod +x mkapikey.js
./mkapikey.js
4SvnAK87DD0t3WMS878UCY-obmADtPeBn6X4gFOtUig
© www.soinside.com 2019 - 2024. All rights reserved.