我正在使用php rand()函数为我的电子商务系统生成优惠券代码。 它工作正常一段时间,但现在我收到很多错误,代码已经存在于系统中。
这是我使用的功能:
function generateRandomString($length) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, strlen($characters) - 1)];
}
return $randomString;
}
我的代码长度为32个字符。
我做了大约150次尝试的样本,发现超过50%的生成代码已经存在于系统中。
我在系统中有4212个代码。具有36个不同符号产生碰撞的32个字符随机字符串的几率基本为零,并且我得到50%的碰撞。
当我通过调用srand();
在我的函数中重新播种随机数生成器时,我没有再发生任何冲突。
但是在php的手册页上,它很清楚地说:
注意:从PHP 4.2.0开始,无需为随机数播种 生成器使用srand()或mt_srand(),因为现在已经完成了 自动。
我正在运行php版PHP 5.5.9
所以我的想法就像播种那样,但每个网络服务器工作者只做一次,然后当进程分叉时,它不会重新播种或类似的东西。 但这显然是apache中的一个错误......
我在apache版本Apache/2.4.7 (Ubuntu)
和mpm_prefork_module
模块中运行php作为apache模块
所以我仍然需要在每个脚本的顶部调用srand()
,这些联系人会说明其他明智的内容,为什么?是apach错误还是PHP?
是的,我知道我不应该为此目的使用此功能,我将更新它以使用加密安全号码。但我认为这不应该发生,我仍然对正在发生的事情感兴趣!
答案 0 :(得分:3)
如果您的代码长度为32个字符,那么为什么不简单地用md5加密当前的microtime?
$coupon = md5( microtime() );
一行简单。如果你想要一点随机性,那就抛出一个
$coupon = md5( microtime() . mt_rand( 0, 10000) );
就像盐一样。这几乎可以保证你永远不会复制。至于为什么它不是随机的。
PHP的随机数生成器每个进程只播种一次。
看到这个帖子......
http://phpsecurity.readthedocs.org/en/latest/Insufficient-Entropy-For-Random-Values.html
顺便说一句,我认为你不需要加密安全的哈希,只有足够随机的,不容易被猜到的。即使使用加密哈希,用户也会将所述哈希输入到优惠券的购物车中,即使是加密安全哈希也是一件简单的事情,那么,你最好只投入时间和# 34; N&#34;尝试,或&#34; n&#34;每秒尝试次数等。为了降低率,可以进行强力攻击。例如,我会尝试32个字符哈希的所有组合。因此,最终并不重要,因为您没有使用明文条目(如密码),然后隐藏您的salting和加密方法。激活的优惠券数量将决定我的成功率和两种情况下的时间......如果你跟随。
在我的答案中暗示是这个
PHP的随机数生成器每个进程只播种一次。分叉不会创建新进程,但会复制当前进程状态。
请参阅
Calling rand/mt_rand on forked children yields identical results
和
http://wiki.openssl.org/index.php/Random_fork-safety
和
http://www.reddit.com/r/shittyprogramming/comments/2jvzgq/sometimes_it_takes_real_shitty_code_to_expose_an/
此外,这不是特定于php的问题,但对于一般的伪随机数生成更是如此。
答案 1 :(得分:2)
显然RNG正在重新接种第一次致电至<{1}}(或明确呼叫rand()
)。
由于srand()
复制了父母的记忆,孩子也会得到父母的种子 - 永远不会重新接种。
答案 2 :(得分:0)
function generateRandomString($length) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, strlen($characters) - 1)];
}
return substr(time().$randomString,0,$length);
}