创建随机哈希/字符串的最佳方法是啥?

Posted

技术标签:

【中文标题】创建随机哈希/字符串的最佳方法是啥?【英文标题】:What is the best way to create a random hash/string?创建随机哈希/字符串的最佳方法是什么? 【发布时间】:2011-01-18 14:49:56 【问题描述】:

为了存储会话而生成哈希的最佳方法是什么?我正在寻找一种轻便、便携的解决方案。

【问题讨论】:

如果您想要安全的随机字符串,请使用 Random::alphanumericString($length) 之类的内容。这是一个随机字符串,而不是哈希。如果你想要一个散列,php 包含了几个算法,但你没有指定你想从什么计算散列。如何将其集成到会话管理中是一个不同的问题。 【参考方案1】:
bin2hex(mcrypt_create_iv(22, MCRYPT_DEV_URANDOM));
    mcrypt_create_iv 会给你一个随机的字节序列。 bin2hex 会将其转换为 ASCII 文本

示例输出:

d2c63a605ae27c13e43e26fe2c97a36c4556846dd3ef

请记住,“最佳”是一个相对术语。您需要在安全性、独特性和速度之间做出权衡。上述示例适用于 99% 的情况,但如果您正在处理特别敏感的数据,您可能需要阅读 difference between MCRYPT_DEV_URANDOM and MCRYPT_DEV_RANDOM。

最后还有一个RandomLib“用于生成各种强度的随机数和字符串”。

请注意,到目前为止,我假设您正在寻找生成一个随机字符串,这与从一个值导出散列不同。对于后者,请参阅password_hash。

【讨论】:

只是一点点 PSA:mcrypt_create_iv 在 PHP 7.1.0 中已被弃用。请改用random_bytes 在 PHP 7.2.0 中删除:secure.php.net/manual/en/intro.mcrypt.php【参考方案2】:

random_bytes() 自 PHP 7.0 起可用(或使用 this polyfill for 5.2 through 5.6)。它在密码学上是安全的(与 notrand() 相比)并且可以与 bin2hex()base64_encode() 或任何其他将二进制转换为对您安全的字符串的函数一起使用用例。

作为十六进制字符串

bin2hex() 将产生一个hexadecimal 字符串,其字符数是随机字节数的两倍(每个十六进制字符代表 4 位,而一个字节中有 8 位)。它只会包含来自abcdef0123456789 的字符,并且长度始终以2 为增量(正则表达式:/^([a-f0-9]2)*$/)。

$random_hex = bin2hex(random_bytes(18));
echo serialize($random_hex);

s:36:"ee438d1d108bd818aa0d525602340e5d7036";

作为 base64 字符串

base64_encode() 将生成一个比随机字节数长 33% 的字符串(每个 base64 字符代表 6 位,而一个字节中有 8 位)。它的长度总是以 4 为增量,= 用于填充字符串的结尾,而以下列表中的字符用于对数据进行编码(不包括我为便于阅读而添加的空格):

abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789
/+

要充分利用可用空间,最好将增量 3 增加到 random_bytes()。结果字符串将匹配/^([a-zA-Z\/+=]4)*$/,尽管= 只能以=== 出现在末尾,并且仅当向random_bytes() 提供一个不是增量为3 的数字时。

$random_base64 = base64_encode(random_bytes(18));
echo serialize($random_base64);

s:24:"ttYDDiGPV5K0MXbcfeqAGniH";

【讨论】:

这种方法是否比创建使用额外特殊字符的字符串有任何优势。我使用一种方法随机生成相同的长度,但具有更大的字符组合,包括数字、大写、小写和特殊字符。这在数学上看起来更安全。 @Zortext random_bytes() 内置于 PHP 中(因此可能比您创建的任何东西都更快)并且可以被认为是加密安全的(与 rand() 相比 不是)。至于bin2hex(),您可以将二进制文件转换为其他文件,而无需过多担心影响安全性(这会更耗时,但可以为最终用户节省一些字节)。最简单的可能是base64_encode(),它只会比二进制输入大约 33%。或者,您可以在映射到字符数组的循环中使用 random_int() @Zortext 如果您担心会话的安全性,请将16 增加到一个让您感觉更好的数字。 16 个字节是 32 个十六进制字符,这意味着有 16^32 不同的可能性,或 3.4e38 种可能性。所以我建议弄清楚你试图阻止的攻击面是什么样子,并相应地调整字节数。如果您担心 cookie/会话使用的存储空间,请使用 base64_encode(),或使用 random_int() 和超过 64 个字符的数组自行开发。【参考方案3】:

您可以使用 PHP 的内置散列函数 sha1md5。选择一个,而不是两个。

有人可能认为同时使用sha1(md5($pass)) 将是一种解决方案。两者都使用不会使您的密码更安全,它会导致冗余数据并且没有多大意义。

看看PHP Security Consortium: Password Hashing,他们给出了一篇很好的文章,其中有弱点并通过散列提高了安全性。

Nonce 代表“n使用一次的数字”。它们用于请求以防止未经授权的访问,它们会发送 secret 密钥并在每次使用您的代码时检查密钥。

您可以在PHP NONCE Library from FullThrottle Development查看更多信息

【讨论】:

谢谢。我去研究一下 SHA1 也可以被破坏(至少在理论上)。有关详细信息,请参阅Hash function security summary。我会选择 SHA256 或 SHA512。 很老的线程,但是SHA1现在被正式破解了! theverge.com/2017/2/23/14712118/…【参考方案4】:

也许 uniqid() 是你需要的?

uniqid — Generate a unique ID

【讨论】:

现在,我正在使用 uniqid() 但我读到在 uniqid() 上使用 md5 并不好。【参考方案5】:

您可以使用openssl_random_pseudo_bytes 从 php 5.3.0 开始生成伪随机字节字符串。您可以使用此函数并使用以下方法之一以某种方式将其转换为字符串:

$bytes = openssl_random_pseudo_bytes(32);
$hash = base64_encode($bytes);

$bytes = openssl_random_pseudo_bytes(32);
$hash = bin2hex($bytes);

第一个将生成最短的字符串,包含数字、小写、大写和一些特殊字符(=、+、/)。第二种选择将生成十六进制数 (0-9, a-f)

【讨论】:

【参考方案6】:

如果可用,请使用random_bytes()

$length = 32;

if (function_exists("random_bytes")) 
    $bytes = random_bytes(ceil($length / 2));
    $token = substr(bin2hex($bytes), 0, $length)

Check it on php.net

【讨论】:

【参考方案7】:

我个人使用 apache 的 mod_unique_id 生成一个随机的唯一编号来存储我的会话。它真的很容易使用(如果你使用 apache)。

请看这里http://en.wikipedia.org/wiki/Cryptographic_nonce,这里甚至还有一个 PHP 库的链接。

【讨论】:

【参考方案8】:

我一般不会手动管理会话 ID。我以前看过一些建议用于混合的东西,我从来没有使用过自己,所以我不能证明它比默认设置更好或更差(注意这是用于自动生成而不是手动管理)。

//md5 "emulation" using sha1
ini_set('session.hash_function', 1);
ini_set('session.hash_bits_per_character', 5);

【讨论】:

我不使用内置的 php 会话函数,因为我对它们没有太多控制权并且可能不安全。 我可以向您保证,它们比您认为安全的任何功能都更安全 :)【参考方案9】:

不同的人会有不同的best方式。但这是我的方式:

    下载此rand-hash.php 文件: http://bit.ly/random-string-generator include() 它在您正在使用的 php 脚本中。然后,只需调用 cc_rand() 函数。默认情况下,它将返回 6 个字符长 可能包含a-z, A-Z,0-9 的随机字符串。你可以通过 length 指定cc_rand() 应该返回多少个字符。

例子:

    cc_rand() 将返回类似:4M8iro

    cc_rand(15) 将返回类似于以下内容的内容:S4cDK0L34hRIqAS

干杯!

【讨论】:

这不会生成加密安全值,因为它使用rand() 但是...如果您不将其用于加密安全值,则此方法效果很好。我只是想在我的程序中为某些东西创建一个标识符。 +1。

以上是关于创建随机哈希/字符串的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

生成用于创建密码检索令牌的随机“站点盐”的好方法是啥?

在 Python 中从字符串数组(或元组)创建动态 sql“in list”子句的“最佳”方法是啥? [复制]

在 python 中创建字符串数组的最佳方法是啥?

使用 .NET 随机化数组的最佳方法

将 json 格式的键值对转换为以符号为键的 ruby​​ 哈希的最佳方法是啥?

将字符串转换为哈希符号的最佳方法