php - 如何使用 PHP 生成强大的唯一 API key ?

标签 php uuid

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

任何人都可以为此提出最佳解决方案吗?我不想用 rand()函数生成随机字符。有替代的解决方案吗?

最佳答案

从 PHP 7.0 开始,您可以使用 random_bytes($length)生成加密安全随机字符串的方法。该字符串将采用二进制格式,因此您需要以某种方式对其进行编码。一个简单的方法是使用 bin2hex($binaryString) .这会给你一个字符串 $length * 2字节长,带有 $length * 8它的一些熵。

你会想要 $length足够高,以便您的 key 实际上无法猜测,并且生成具有相同值的另一个 key 的可能性几乎为零。

把这一切放在一起,你得到这个:

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

验证 API key 时,仅使用前 32 个字符从数据库中选择记录,然后使用 hash_equals()将用户提供的 API key 与您存储的值进行比较。这有助于防止定时攻击。 ParagonIE 有 an excellent write-up在这一点上。

对于检查逻辑的示例:
$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 位(而不是十六进制的 4 位),这可能会使编码值在末尾带有填充。

为了避免这个答案拖延,我将在没有支持论据的情况下提出一些处理 Base64 的建议。选择一个 $length大于 32 可以被 3 和 2 整除。我喜欢 42,所以我们将把它用于 $length . Base64 编码的长度为 4 * ceil($length / 3) , 所以我们的 $key将是 56 个字符长。您可以使用前 28 个字符从您的存储中进行选择,在末尾留下另外 28 个字符,这些字符可以通过 hash_equals 防止受到定时攻击的泄漏。 .

奖励 2:安全 key 存储

理想情况下,您应该像对待密码一样对待 key 。这意味着,而不是使用 hash_equals要比较完整的字符串,您应该像密码一样散列 key 的其余部分,将其与 key 的前半部分(纯文本)分开存储,使用前半部分从数据库中进行选择并验证后半部分一半用password_verify .

关于php - 如何使用 PHP 生成强大的唯一 API key ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21378988/

相关文章:

php - 为什么这个 PDO 语句会默默地失败?

php - 如何选择IP并查看插入时间是否不少于2分钟

php - 条件计数 MySQL

php - YouTube Api(V2.0 或 3.0)获取给定 channel url 的 channel 信息

Java:一个 UUID 生成单例

php - ci : google indexing address with index. php 但站点中没有与 index.php 的链接

java - Java 中空 ("nil") UUID 的实例

python - PostgreSQL UUID 日期类型

javascript - 使用 mongodb 收集 meteor 时出现重复的键

python - SQLAlchemy - 如何在提交/更新/查询之前获取对象的 UUID 可用?