如何在 PHP 中生成唯一的安全随机字符串?

How to generate unique secure random string in PHP?

我想添加随机字符串作为表单提交的标记,它永远是唯一的。我在 Google 上花了很多时间,但我对使用哪个组合感到困惑?

我在谷歌搜索时发现了很多方法:

1) Combination of character and number.

2) Combination of character, number and special character.

3) Combination of character, number, special character and date time.

我可以使用哪种组合?

我可以生成多少个随机字符串字符?

还有其他安全的方法请告诉我吗?

你应该选择 3 个选项。因为它有日期和时间,所以它每次都变得独一无二。 对于方法,您尝试过

str_shuffle($string)

每次它从 $string 生成随机字符串。 结束然后使用 substr

($string, 开始, 结束)

减少它。 如果需要日期和时间则结束,然后将结果字符串与其连接。

根据您的需要,您肯定可以变得更漂亮,但我会把它扔在那里,因为这是我经常用于诸如您所描述的内容的东西:

md5(rand());

它快速、简单且易于记忆。由于它是十六进制的,因此可以很好地与其他人一起使用。

尝试代码,对于函数 getUniqueToken(),其中 returns 是长度为 10(默认)的唯一字符串。

/*
    This function will return unique token string...
*/
function getUniqueToken($tokenLength = 10){
    $token = "";
    //Combination of character, number and special character...
    $combinationString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*#&$^";
    for($i=0;$i<$tokenLength;$i++){
        $token .= $combinationString[uniqueSecureHelper(0,strlen($combinationString))];
    }
    return $token;
}

/*
    This helper function will return unique and secure string...
*/
function uniqueSecureHelper($minVal, $maxVal) {
        $range = $maxVal - $minVal;
        if ($range < 0) return $minVal; // not so random...

        $log = log($range, 2);
        $bytes = (int) ($log / 8) + 1; // length in bytes
        $bits = (int) $log + 1; // length in bits
        $filter = (int) (1 << $bits) - 1; // set all lower bits to 1

        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
            $rnd = $rnd & $filter; // discard irrelevant bits
        } while ($rnd >= $range);
        return $minVal + $rnd;
}

使用此代码(两个函数),您可以通过传递 int 参数来增加字符串长度,例如 getUniqueToken(15)

我使用你的第二个想法(字符、数字和特殊字符的组合),你在谷歌搜索后对其进行了改进。希望我的例子对你有所帮助。

参考这个SO Protected Question。这可能就是您正在寻找的。

我认为最好将您重定向到之前提出的问题,该问题具有更多实质性内容 answers.You 会找到很多选项。

这里有一些注意事项:

字母表

字符数可以认为是alphabet进行编码。它本身不会影响字符串强度,但较大的字母表(数字、非字母数字字符等)确实允许具有相似强度的较短字符串(又名 keyspace),因此如果您正在寻找它会很有用对于较短的字符串。

输入值

为了保证您的字符串是唯一的,您需要添加一些保证唯一的内容。

  • 如果你有一个好的随机数生成器,随机值是一个很好的种子值
  • 时间是一个很好的种子值,但在高流量环境中可能不是唯一的
  • 如果您假设用户不会同时创建会话,则用户 ID 是一个很好的种子值
  • 唯一ID是系统保证唯一的。这通常是服务器将保证/验证是唯一的,无论是在单个服务器部署还是分布式部署中。一种简单的方法是添加机器 ID 和机器唯一 ID。一种更复杂的方法是将键范围分配给机器并让每台机器管理它们的键范围。

我使用过的需要绝对唯一性的系统添加了一个服务器唯一 ID,以保证项目是唯一的。这意味着不同服务器上的相同项目将被视为不同,这正是这里想要的。

接近

再选择一个符合您的唯一性要求的输入值。如果你需要永远的绝对唯一性,你需要你控制的东西,你确定它是唯一的,例如机器相关号码(不会与分布式系统中的其他号码冲突)。如果您不需要绝对唯一性,您可以使用带有其他值(例如时间)的随机数。如果需要随机性,加个随机数。

使用符合您的用例的字母表/编码。对于机器 ID,十六进制和 base 64 等编码很流行。对于机器可读的 ID,对于不区分大小写的编码,我更喜欢 base32 (Crockford) 或 base36,对于区分大小写的编码,我更喜欢 base58 或 base62。这是因为这些 base32、36、58 和 62 生成较短的字符串,并且(与 base64 相比)在多种用途(例如 URL、XML、文件名等)中是安全的,并且不需要在不同用途之间进行转换案例。

对于唯一字符串使用 uniqid().

为了确保安全,请使用散列算法

例如:

echo md5(uniqid())