生成API密钥的最佳方法


89

因此,现在有许多不同的服务,例如Google API,Twitter API,Facebook API等。

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

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

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

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

编辑: 我已经和几个朋友(电子邮件/推特)进行了交流,他们建议只使用带有破折号的GUID。

不过,这对我来说似乎有点不客气,希望能得到更多的想法。


我已经在这里回答了更多详细信息..生成密钥并将其用作hmac auth
Anshu Kumar

Answers:


58

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

这是一个C#示例:

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

2
这不是很安全,获得对您的数据库访问权限的攻击者可以获得密钥。最好将密钥生成为用户特有的某种哈希(例如盐)的哈希值,并结合服务器机密。
James Wierzba

13
存储随机生成的API密钥与存储哈希密码具有相同的安全性。在大多数情况下,这很好。如您所建议,可以将随机生成的数字视为一个盐,然后使用服务器密钥对其进行哈希处理;但是,这样做会在每次验证时产生哈希开销。如果不使所有API密钥无效,也无法使服务器机密无效。
爱德华·布雷

不错的解决方案,但您可能需要在apiKey之前使用var关键字:) var apiKey = Convert.ToBase64String(key);
戴维·奥希亚

@ JohnM2对。由于apiKey可以在其他地方声明,因此我一直保持开放性。为了清楚起见,我添加了该类型。
爱德华·布雷

4
@JamesWierzba,如果被攻击者已经存在于您的数据库中,那么他们对您的API的不安全访问可能是您所担心的最少……
Jon Story

29

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

  • 唯一地标识授权的API用户-“ API密钥”的“密钥”部分
  • 验证用户身份-无法猜测/伪造
  • 如果用户行为不当,可以将其撤消-通常,他们键入可以删除记录的数据库。

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

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

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

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

并使用私人秘密对其进行签名。

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

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


或随机字符串的哈希

散列并不能防止伪造。 签名可以确保密钥来自您。


3
如果对照提供API的服务器上已注册的API密钥的数据库检查了客户端提供的API密钥,则算法的签名步骤是否必要?如果服务器是提供密钥的服务器,那么似乎签名在这里是多余的。
sappenin

3
@sappenin,是的。如果将不可猜测的密钥存储在服务器上,则无需防止伪造。通常API的请求是由机器的一个农场中的任何一个处理-服务器是众多服务器之一。签名检查可以在任何机器上完成,而无需往返数据库,这在某些情况下可以避免争用情况。
Mike Samuel

1
@MikeSamuel如果API密钥已签名并且您没有往返数据库,那么当密钥被撤销但仍用于访问API时会发生什么?
Abhyudit Jain'2

@AbhyuditJain,在任何分布式系统中,您都需要一个一致的消息顺序(后续使用被撤消的凭据之前,发生撤消)或其他方式来限制歧义。某些系统不会在每个请求上都往返-如果节点将密钥存储在数据库中的事实缓存10分钟,则只有10分钟。攻击者可以在其中滥用已吊销凭证的窗口。但是,可能会造成混乱:用户撤销凭证,然后测试其是否已撤销,并且由于非粘性会话导致两个请求转到不同的节点而感到惊讶。
Mike Samuel

5

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

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

API密钥可能会遭到破坏,在这种情况下,用户可能希望取消其API密钥并生成一个新的API密钥,因此您的密钥生成方法必须能够满足此要求。


15
不要以为UUID很难猜测;它们不应用作安全功能(UUID规范RFC4122第6节)。API密钥需要一个安全的随机数,但是UUID并非绝对不可猜测
爱德华·布雷

3
@EdwardBreyUUID uuid = UUID.randomUUID();在Java中如何?您是说随机性还不够好吗?
微小的

8
@MicroR仅当用于使其成为随机数的随机数生成器在密码上安全且128位足够时,该随机UUID才是安全的。尽管UUID RFC不需要安全的随机数生成器,但是给定的实现可以自由使用。在randomUUID的情况下,API文档特别声明它使用“加密强度高的伪随机数生成器”。因此,对于128位API密钥,该特定实现是安全的。
爱德华·布雷

4

如果只需要一个字母数字字符的API密钥,则可以使用base64-random方法的变体,而只能使用base-62编码。base-62编码器基于

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,但这是一个古老的故事。


4
Windows 2000使用随机数切换到GUID 。但是,不能保证不能预测随机数。例如,如果攻击者为自己创建了几个API密钥,则有可能确定将来用于生成另一个用户的API密钥的随机数。通常,不要认为UUID是绝对不可猜测的
爱德华·布雷
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.