如何使用PHP生成强大的唯一API密钥?

时间:2014-01-27 10:55:34

标签: php uuid

我需要生成一个强大的唯一API密钥。

有人能为此建议最佳解决方案吗?我不想使用rand()函数来生成随机字符。有替代解决方案吗?

5 个答案:

答案 0 :(得分:5)

从PHP 7.0开始,您可以使用random_bytes($length)方法生成加密安全的随机字符串。这个字符串将是二进制的,所以你想要以某种方式编码它。一种直截了当的方法是使用bin2hex($binaryString)。这将为您提供一个长$length * 2个字节的字符串,其中包含$length * 8个熵。

您希望$length足够高,以使您的密钥有效无法使用,并且使用相同值生成另一个密钥的可能性几乎为零。

把这一切放在一起,你就明白了:

$key = bin2hex(random_bytes(32)); // 64 characters long

验证API密钥时,仅使用前32个字符从数据库中选择记录,然后使用hash_equals()将用户指定的API密钥与存储的值进行比较。这有助于防止定时攻击。 ParagonIE对此有https://stackoverflow.com/users/2830850/tarun-lalwani

有关检查逻辑的示例:

$token = $request->bearerToken();

// Retrieve however works best for your situation,
// but it's critical that only the first 32 characters are used here.
$users = app('db')->table('users')->where('api_key', 'LIKE', substr($token, 0, 32) . '%')->get();

// $users should only have one record in it,
// but there is an extremely low chance that
// another record will share a prefix with it.
foreach ($users as $user) {
    // Performs a constant-time comparison of strings,
    // so you don't leak information about the token.
    if (hash_equals($user->api_token, $token)) {
        return $user;
    }
}

return null;

奖励:使用Base64编码略微更高级

出于空间原因,使用Base64编码优于十六进制,但稍微复杂一点,因为每个字符编码6位(而不是16位十六进制),这可以使编码值在末尾留下填充。

为了保持这个答案不被拖延,我只是提出一些处理Base64的建议而没有他们的支持论点。选择一个大于32的$length可以被3和2整除。我喜欢42,所以我们将$length使用它。 Base64编码的长度为4 * ceil($length / 3),因此我们的$key长度为56个字符。您可以使用前28个字符从存储中进行选择,最后留下另外28个字符,以防止因hash_equals的时间攻击而泄露。

奖励2:安全密钥存储

理想情况下,您应该像密码一样对待密钥。这意味着不是使用hash_equals来比较完整字符串,而是应该像密码一样对密钥的其余部分进行哈希处理,而不是以密钥的前半部分(以纯文本格式)存储,使用上半部分从您的数据库中进行选择,并使用password_verify验证后半部分。

答案 1 :(得分:1)

您可以尝试使用uniqid功能。

  

uniqid - 生成唯一ID

     

string uniqid ([ string $prefix = "" [, bool $more_entropy = false ]] )

答案 2 :(得分:-2)

使用mcrypt:

<?php
$bytes  = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
$unpack = unpack("Nint", $bytes);
$id     = $unpack['int'] & 0x7FFFFFFF;

答案 3 :(得分:-3)

PHP具有带有可选前缀的uniqid函数http://php.net/manual/en/function.uniqid.php,您甚至可以添加额外的熵以进一步避免冲突。但是,如果你绝对需要一些独特的东西,你就不应该使用任何随机性的东西。

答案 4 :(得分:-8)

这是我找到的最佳解决方案。