这是一个很长的问题,所以简短的问题是,依靠PHP的rand
函数生成第一次密码是否安全?
在我的空闲时间,我只是在考虑制作非常困难的自定义密码生成器(仅限数字)的逻辑,这是我在下一个项目中可能需要的一项功能。
首先要记住的是PHP的rand()
方法。我尝试了几个围绕rand
方法的测试来测试它的随机行为。一般来说,首先要想到的是,生成多个随机数并对其进行一些操作会使随机数更难以猜测。我很惊讶地看到使用以下程序,随机数的平均值非常接近其一半:
$minAvg=$maxAvg=50;
for($i=1;$i<=1000;$i++){
//Random average
$sum=0;
for($j=0;$j<1000;$j++){
$sum=$sum+rand(1,100);
}
$avg=$sum/1000;
///
if($avg<$minAvg){
$minAvg=$avg;
}
if($avg>$maxAvg){
$maxAvg=$avg;
}
if($i%100==0)
{
echo "at i=$i, Min Avg = $minAvg and Max Avg = $maxAvg <br/>";
}
}
上述代码的一个输出是:
at i=100, Min Avg = 47.174 and Max Avg = 53.003
at i=200, Min Avg = 47.174 and Max Avg = 53.003
at i=300, Min Avg = 47.174 and Max Avg = 53.003
at i=400, Min Avg = 47.174 and Max Avg = 53.003
at i=500, Min Avg = 47.174 and Max Avg = 53.192
at i=600, Min Avg = 47.174 and Max Avg = 53.192
at i=700, Min Avg = 47.174 and Max Avg = 53.192
at i=800, Min Avg = 47.174 and Max Avg = 53.192
at i=900, Min Avg = 47.174 and Max Avg = 53.204
at i=1000, Min Avg = 47.174 and Max Avg = 53.204
我在代码上运行至少50次,但即使在1000次迭代后,平均值始终保持在47.xx到53.xx之间(对于1和100之间的随机数)
虽然这个结果并没有说明很多,因为通常平均几个数字必须接近中间,但我没想到随机数的相同行为。 我觉得它显示PHP的rand()使用一些固定的算法,它在给定的模式中生成数字。据我了解,这只是平均值保持在中间位置的合理理由。
直到现在我经常使用随机数生成第一次密码(在首次登录时强行更改)。但是现在我担心使用随机数生成第一次涉及金融交易和敏感信息(如信用卡号码)的网站密码是安全的。黑客(不是业余的但是专业的黑客)是否有可能轻易破解这些密码?最重要的是,是否有任何算法可以检测(或至少估计)下一个随机数。
修改
为了使其更加明智,用户将在线下注册,例如打开银行账户,printed first time password
将通过邮寄,而不是通过电子邮件发送。因此密码必须保持在10个字符以下才能排除任何加密。
答案 0 :(得分:3)
rand()
不是加密强度的RNG,但这并不重要。
随机密码所需要的是,它应该是不可预测的,随机猜测是不可行的。此属性与密码的长度和允许字符池有很大关系,而不是与rand()
有关。
此外,针对暴力强制的最佳防线是在登录尝试之间引入故意延迟。如果你这样做并且拥有“合理随机”的密码,那么绝对没有办法强迫你使用。
最后,我们使用linear congruential generator来实现rand()
。除非服务器将花费大部分时间来生成密码(非常值得怀疑),否则切换到mt_rand()
Mersenne Twister即可实现“更好”的随机性,这是{{3}}的实现(它仍然不是密码强度) )。
答案 1 :(得分:1)
PHP uniqid正是您要找的。用法示例:
$code = uniqid(rand(), true);
请注意,有一个更安全的功能openssl_random_pseudo_bytes()但它仅适用于PHP&gt; 5.3
答案 2 :(得分:1)
在php中生成安全随机数的一种相对简单的方法是mcrypt_create_iv
,MCRYPT_DEV_URANDOM
为$source
。即mcrypt_create_iv(size, MCRYPT_DEV_URANDOM)
。然后将生成的随机字节转换为您需要的任何形式。
答案 3 :(得分:0)
在你关注之前阅读问题,然后阅读以下内容作为问题的解决方案,谢谢。
你正在做一些比密码可预测性更不安全的事情,比如使用电子邮件发送“第一次”密码。
你坚持使用生成密码,或者使用另一种方法发送第一次自动登录URL(我建议),你仍然需要防止URL的密码或密钥的可预测性。
你需要有这么长的秘密盐(键盘随机很好):
$salt="aslkfhaqoiey19836y9qasdhkasjdhbknmxcbnzmbAkua089610"
。
然后使用rand()创建您的URL的首次密码或密钥,但与md5和非常长的盐一起使用。由于盐是秘密的,没有人能预测md5会产生什么。
$randomPassword=base64_encode(md5(rand().rand().$salt, true));