我想创建一个令牌生成器,该令牌生成器生成用户无法猜到且仍然唯一的令牌(用于密码重置和确认码)。
我经常看到这段代码;它有意义吗?
md5(uniqid(rand(), true));
根据comment uniqid($prefix, $moreEntopy = true)
收益
前8个十六进制字符= Unix时间,最后5个十六进制字符=微秒。
我不知道如何处理$prefix
- 参数..
因此,如果您未将$ moreEntopy标志设置为true,则会提供可预测的结果。
问题: 但是如果我们将uniqid
与$moreEntopy
一起使用,那么使用md5对它进行哈希购买会给我们带来什么?它是否优于:
md5(mt_rand())
edit1:我会将此令牌存储在具有唯一索引的数据库列中,因此我将检测列。可能有兴趣/
答案 0 :(得分:43)
rand()存在安全隐患,永远不应该用于生成安全令牌:rand() vs mt_rand()(请查看“静态”图像)。但是这些生成随机数的方法都不是加密安全的。要生成安全的secerts,应用程序需要访问平台,操作系统或硬件模块提供的CSPRNG。
在Web应用程序中,安全机密的良好来源是对/dev/urandom
等熵池的非阻塞访问。从PHP 5.3开始,PHP应用程序可以使用openssl_random_pseudo_bytes()
,Openssl库将根据您的操作系统选择最佳的熵源,在Linux下,这意味着应用程序将使用/dev/urandom
。这code snip from Scott is pretty good:
function crypto_rand_secure($min, $max) {
$range = $max - $min;
if ($range < 0) return $min; // 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 $min + $rnd;
}
function getToken($length=32){
$token = "";
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
$codeAlphabet.= "0123456789";
for($i=0;$i<$length;$i++){
$token .= $codeAlphabet[crypto_rand_secure(0,strlen($codeAlphabet))];
}
return $token;
}
答案 1 :(得分:21)
这是我发现的另一个问题的副本,在此之前几个月被问到。以下是问题和答案的链接:https://stackoverflow.com/a/13733588/1698153。
我不同意接受的答案。根据PHP自己的网站"[uniqid] does not generate cryptographically secure tokens, in fact without being passed any additional parameters the return value is little different from microtime(). If you need to generate cryptographically secure tokens use openssl_random_pseudo_bytes()."
我认为答案可能比这更清楚,uniqid
不安全。
答案 2 :(得分:5)
我知道问题已经过时了,但它出现在Google上,所以...
正如其他人所说,rand()
,mt_rand()
或uniqid()
不会保证您的独特性......即使openssl_random_pseudo_bytes()
也不应该使用,因为它使用deprecated features of OpenSSL }。
用于生成随机哈希(与md5相同)的内容是random_bytes()(在PHP7中引入)。要生成与MD5长度相同的哈希:
bin2hex(random_bytes(16));
如果您使用的是PHP 5.x,则可以通过添加random_compat library来获得此功能。
答案 3 :(得分:1)
定义“独特”。如果你的意思是两个令牌不能具有相同的值,那么散列是不够的 - 它应该通过唯一性测试来支持。您为散列算法提供唯一输入这一事实并不能保证唯一的输出。
答案 4 :(得分:1)
要回答你的问题,问题是你不能让发电机本身保证随机和独特,即md5(mt_rand())
可能导致重复。你想要的是“随机出现”的独特价值观。 uniqid给出了唯一的id,rand()附加了一个随机数字,使其更难猜测,md5掩盖了结果,使其更难猜测。没有什么是不可能的。我们只需要努力让他们甚至不想尝试。
答案 5 :(得分:1)
答案 6 :(得分:0)
首先,此类过程的范围是创建一个键/哈希/代码,对于一个给定的数据库将是唯一的。在特定时刻,不可能为整个世界创造独特的东西。
话虽这么说,您应该使用自定义字母创建一个普通的可见字符串,并根据您的数据库(表)检查创建的代码。
如果该字符串是唯一的,那么您将md5()
应用于该字符串,并且任何人或任何脚本都无法猜到。
我知道,如果你深入研究加密生成理论,你可以找到关于这种代码生成的大量解释,但是当你把它用于实际用法时,它真的不那么复杂。
这是我用来生成一个简单的10位唯一代码的代码。
$alphabet = "aA1!bB2@cC3#dD5%eE6^fF7&gG8*hH9(iI0)jJ4-kK=+lL[mM]nN{oO}pP\qQ/rR,sS.tT?uUvV>xX~yY|zZ`wW$";
$code = '';
$alplhaLenght = strlen($alphabet )-1;
for ($i = 1; $i <= 10; $i++) {
$n = rand(1, $alplhaLenght );
$code .= $alphabet [$n];
}
以下是一些生成的代码,尽管您可以自己运行它以查看它的工作原理:
SpQ0T0tyO%
UWN [MU] [。
D | [ROt + Cd @
O6I | w38TRe
当然,可以应用很多“改进”来使其更加“复杂”,但是如果你对它应用md5()
,它就会变成,让我们说吧“不可思议的”。 :)
答案 7 :(得分:-1)
MD5是用于生成数据相关 ID的不错算法。但是如果您有多个具有相同比特流(内容)的项目,您将生成两个类似的MD5“ID”。
因此,如果您只是将它应用于rand()
函数,保证不会创建两次相同的数字,那么您就非常安全了。
但是为了更强大的密钥分发,我个人会使用SHA1或SHAx等......但是你仍然会遇到类似数据导致类似密钥的问题。