88

为了生成一个 32 字符的令牌来访问我们目前使用的 API:

$token = md5(uniqid(mt_rand(), true));

我已经读到这种方法在加密上并不安全,因为它基于系统时钟,这openssl_random_pseudo_bytes将是一个更好的解决方案,因为它更难预测。

如果是这种情况,等效代码会是什么样子?

我猜是这样的,但我不知道这是否正确......

$token = md5(openssl_random_pseudo_bytes(32));

另外,我应该传递给函数的长度是多少?

4

5 回答 5

197

这是正确的解决方案:

$token = bin2hex(openssl_random_pseudo_bytes(16));

# or in php7
$token = bin2hex(random_bytes(16));
于 2013-09-19T08:57:41.210 回答
10

如果您想使用 openssl_random_pseudo_bytes 最好使用 CrytoLib 的实现,这将允许您生成所有字母数字字符,在 openssl_random_pseudo_bytes 周围粘贴 bin2hex 只会导致您获得 AF(大写字母)和数字。

将 path/to/ 替换为您放置 cryptolib.php 文件的位置(您可以在 GitHub 上找到它:https ://github.com/IcyApril/CryptoLib )

<?php
  require_once('path/to/cryptolib.php');
  $token = IcyApril\CryptoLib::randomString(16);
?>

完整的 CryptoLib 文档位于:https ://cryptolib.ju.je/ 。它涵盖了许多其他随机方法,级联加密以及哈希生成和验证;但如果你需要它就在那里。

于 2014-12-29T00:45:08.263 回答
9

如果你有一个加密安全的随机数生成器,你不需要散列它的输出。事实上你不想。只需使用

$token  = openssl_random_pseudo_bytes($BYTES,true)

但是,其中 $BYTES 是您想要的许多字节数据。MD5 有一个 128 位的散列,所以 16 个字节就可以了。

附带说明一下,您在原始代码中调用的所有函数都不是密码安全的,大多数都足够有害,即使与安全的其他函数结合使用,仅使用一个也会破坏是不安全的。MD5 存在安全问题(尽管对于此应用程序,它们可能不相关)。Uniqid 不仅默认情况下不生成加密随机字节(因为它使用系统时钟),而且您传入的附加熵使用线性全等生成器组合,这在加密上不安全。实际上,这可能意味着即使他们不知道您的服务器时钟的值,也可以猜测您的所有 API 密钥,即使他们可以访问其中的一些。最后,用作额外熵的 mt_rand() 也不是安全的随机数生成器。

于 2013-09-17T04:56:51.510 回答
0

另一种选择是使用来自 ircmaxell 的 RandomLib ( https://github.com/ircmaxell/RandomLib )

安装:composer require ircmaxell/random-lib

中等强度示例

$factory = new Factory();
$factory->getMediumStrengthGenerator()->generateString(32);
于 2021-09-03T14:54:27.883 回答
-2

可靠的密码您只能使用ascii字符a-zA-Z数字 0-9。要做到这一点,最好的方法是仅使用加密安全的方法,例如PHP7 中的random_int()random_bytes()。其余函数作为base64_encode()您只能将其用作支持函数以使字符串可靠并将其更改为ASCII字符。

mt_rand()不安全而且很旧。从任何字符串您必须使用 random_int()。从二进制字符串你应该使用base64_encode()来使二进制字符串可靠或 bin2hex,但是你只会将字节切割到 16 个位置(值)。 请参阅我对此功能的实现。它使用所有语言。

于 2018-05-02T14:20:13.670 回答