在 php 中生成加密安全的随机数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1041509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generate cryptographically secure random numbers in php
提问by caw
PHP's rand()function doesn't give good random numbers. So I started to use mt_rand()which is said to give better results. But how good are these results? Are there any methods to improve them again?
PHP 的rand()函数不能提供好的随机数。所以我开始使用mt_rand()据说效果更好的。但这些结果有多好?有什么方法可以再次改进它们吗?
My idea:
我的点子:
function rand_best($min, $max) {
$generated = array();
for ($i = 0; $i < 100; $i++) {
$generated[] = mt_rand($min, $max);
}
shuffle($generated);
$position = mt_rand(0, 99);
return $generated[$position];
}
This should give you "perfect" random numbers, shouldn't it?
这应该给你“完美”的随机数,不是吗?
回答by coobird
Pseudorandom number generators(PRNG) are very complex beast.
伪随机数生成器(PRNG) 是非常复杂的野兽。
There are no real "perfect" random number generators -- in fact the best that can be done from mathematical functions are pseudorandom -- they seem random enough for most intents and purposes.
没有真正的“完美”随机数生成器——事实上,最好的数学函数是伪随机的——它们对于大多数意图和目的来说似乎足够随机。
In fact, performing any additional actions from a number returned by a PRNG doesn't really increase its randomness, and in fact, the number can become less random.
实际上,从 PRNG 返回的数字执行任何其他操作并不会真正增加其随机性,实际上,该数字可能会变得不那么随机。
So, my best advice is, don't mess around with values returned from a PRNG. Use a PRNG that is good enough for the intended use, and if it isn't, then find a PRNG that can produce better results, if necessary.
所以,我最好的建议是,不要乱用从 PRNG 返回的值。使用足以满足预期用途的 PRNG,如果不是,则在必要时找到可以产生更好结果的 PRNG。
And frankly, it appears that the mt_randfunction uses the Mersenne twister, which is a pretty good PRNG as it is, so it's probably going to be good enough for most casual use.
坦率地说,该mt_rand函数似乎使用了Mersenne twiner,这是一个非常好的 PRNG,因此对于大多数休闲使用来说它可能已经足够了。
However, Mersenne Twister is not designed to be used in any security contexts. See this answerfor a solution to use when you need randomness to ensure security.
但是,Mersenne Twister 并非设计用于任何安全环境。请参阅此答案,了解在需要随机性以确保安全性时使用的解决方案。
Edit
编辑
There was a question in the comments why performing operations on a random number can make it less random. For example, some PRNGs can return more consistent, less random numbers in different parts of the bits -- the high-end can be more random than the low-end.
评论中有一个问题,为什么对随机数执行操作可以使其不那么随机。例如,某些 PRNG 可以在位的不同部分返回更一致、更少随机数——高端可能比低端更随机。
Therefore, in operations where the high-end is discarded, and the low end is returned, the value can become less random than the original value returned from the PRNG.
因此,在丢弃高端并返回低端的操作中,该值可能变得比从 PRNG 返回的原始值更不随机。
I can't find a good explanation at the moment, but I based that from the Java documentation for the Random.nextInt(int)method, which is designed to create a fairly random value in a specified range. That method takes into account the difference in randomness of the parts of the value, so it can return a better random number compared to more naive implementations such as rand() % range.
我目前找不到很好的解释,但我基于该Random.nextInt(int)方法的 Java 文档,该方法旨在在指定范围内创建一个相当随机的值。该方法考虑了值各部分的随机性差异,因此与更幼稚的实现(例如 )相比,它可以返回更好的随机数rand() % range。
回答by Salvador Dali
Quick answer:
快速回答:
In a new PHP7there is a finally a support for a cryptographically secure pseudo-random integers.
在新的PHP7 中,终于支持加密安全的伪随机整数。
int random_int ( int $min , int $max )
There is also a polyfill for PHP5x.
还有一个用于 PHP5x 的 polyfill。
Longer answer
更长的答案
There is no perfect random number generator, and computers use pseudorandom number generatorto create sequences that looks random. The sequences look random (and pass some randomness tests) but because there is some algorithm to generate it, you can repeat algorithm with absolutely the same states and get the same result.
没有完美的随机数生成器,计算机使用伪随机数生成器来创建看起来随机的序列。序列看起来是随机的(并通过了一些随机性测试),但是因为有一些算法可以生成它,所以您可以使用完全相同的状态重复算法并获得相同的结果。
The same advice as with cryptography"do not invent your own cypher" can be translated to random number generators and mean that you can not just get a lot of random number generators combined together and get expect to get a better generator.
与密码学相同的建议“不要发明自己的密码”可以转换为随机数生成器,这意味着您不能只是将大量随机数生成器组合在一起,并期望获得更好的生成器。
One of the subsets of random number generators is cryptographically secure random number generators:
随机数生成器的子集之一是加密安全的随机数生成器:
The requirements of an ordinary PRNG are also satisfied by a cryptographically secure PRNG, but the reverse is not true. CSPRNG requirements fall into two groups: first, that they pass statistical randomness tests; and secondly, that they hold up well under serious attack, even when part of their initial or running state becomes available to an attacker
密码安全的 PRNG 也可以满足普通 PRNG 的要求,但反之则不然。CSPRNG 要求分为两组:第一,它们通过统计随机性测试;其次,即使它们的初始或运行状态的一部分可供攻击者使用,它们也能承受严重的攻击
So this is pretty close to your definition of "perfect". One more time under no condition (except of learning how to do cryptography) you should try to implement one of that algorithms and use it in your system.
所以这非常接近你对“完美”的定义。再一次在没有条件的情况下(除了学习如何进行密码学),您应该尝试实现其中一种算法并在您的系统中使用它。
But luckily PHP7has it implemented,
但幸运的是PHP7已经实现了,
int random_int ( int $min , int $max )
Generates cryptographic random integers that are suitable for use where unbiased results are critical (i.e. shuffling a Poker deck).
生成适用于无偏结果至关重要的加密随机整数(即洗牌扑克牌)。
The sources of random are as follows:
随机的来源如下:
- On Windows CryptGenRandom() is used exclusively
- arc4random_buf() is used if it is available (generally BSD specific)
- /dev/arandom is used where available
- The
getrandom(2)syscall (on newer Linux kernels) - /dev/urandom is used where none of the above is available
- 在 Windows 上 CryptGenRandom() 专门使用
- 如果可用,则使用 arc4random_buf()(通常特定于 BSD)
- /dev/arandom 在可用的地方使用
- 该
getrandom(2)系统调用(较新的Linux内核) - /dev/urandom 用于上述任何一项都不可用的情况
This makes all the previous answers obsolete (and some deprecated).
这使得之前的所有答案都过时了(并且有些已被弃用)。
回答by Peter
I'm not sure that what you've done "improves" the randomness. From what I can understand you generate 100 random numbers and then randomly pick one of them.
我不确定您所做的是否“改善”了随机性。据我所知,您生成 100 个随机数,然后随机选择其中一个。
From what I can remember from my probability course, this probably doesn't increase the randomness, as if there is an underlying bias in the generator function (mt_rand()), then it will still be reflected somehow in the output.
根据我在概率课程中的记忆,这可能不会增加随机性,好像生成器函数 (mt_rand()) 中存在潜在偏差,那么它仍然会以某种方式反映在输出中。
回答by truppo
In what way is mt_rand() "bad"?
mt_rand() 以什么方式“坏”?
For example: If it favors a certain number. Lets say mt_rand(1, 10) favours low numbers in the range, ie "1" and "2" occurs on average more than 10% each. Then your "improvement" would still suffer from the same problem.
例如:如果它偏爱某个数字。假设 mt_rand(1, 10) 偏爱范围内的低数,即“1”和“2”平均出现超过 10%。那么你的“改进”仍然会遇到同样的问题。
Selecting a random number out of a faulty sequence will still be faulty.
从错误的序列中选择一个随机数仍然是错误的。
回答by mandroid
<?php
function random_number(){
return 4; // return generated number
// guaranteed to be random
}
?>
All joking aside, you're getting into a philosophical question of what is "random" or what is "best". Ideally you'd want your random numbers to have few patterns in them over the course of your procedure. Generally system time is used as the seed, but I've also used the previous random number as the seed, the previous random numberth ago as the seed. The problem is, with a powerful enough computer and full knowledge of the hardware running, and generator function, you would be able to predict the entire set of numbers generated. Thus if you had a powerful enough computer (some people put God into this category) that knew all possible variables and functions of the universe you would then be able to predict every event that happened or will happen. Most random number generators are fine on their own but if you know someone who can see the patterns, more likely they are like the guy in Beautiful Mind and you should get them checked into a clinic.
撇开所有玩笑不谈,您会陷入一个哲学问题,即什么是“随机”或什么是“最佳”。理想情况下,您希望随机数在整个过程中几乎没有模式。一般使用系统时间作为种子,但我也使用了之前的随机数作为种子,之前的随机数作为种子。问题是,有了足够强大的计算机和对运行的硬件和生成器功能的全面了解,您将能够预测生成的整个数字集。因此,如果你有一台足够强大的计算机(有些人把上帝归入这一类),它知道宇宙所有可能的变量和功能,那么你就能够预测已经发生或将要发生的每一个事件。
根据大众需求:D
回答by elliot
I wrote a cronjob that gets 1000 numbers from random.org periodically (say, once an hour) and added them into a PHP array. Whenever I want random numbers in my script, I use mt_rand(0,1000) to call a number from that. A few extra microseconds of overhead, but I get truly random numbers based on natural atmospheric noise.
我编写了一个 cronjob,它定期(例如,每小时一次)从 random.org 获取 1000 个数字并将它们添加到 PHP 数组中。每当我想在脚本中使用随机数时,我都会使用 mt_rand(0,1000) 从中调用一个数字。额外的几微秒开销,但我得到了基于自然大气噪声的真正随机数。
回答by Thinker
It all depends what for you need that random number :) For me ShuffleBagis the best one :)
这一切都取决于你需要什么随机数:) 对我来说ShuffleBag是最好的:)
回答by Gerry
Edit: My comment is no longer valid. Please see the following answer: https://stackoverflow.com/a/31443898/109561
编辑:我的评论不再有效。请参阅以下答案:https: //stackoverflow.com/a/31443898/109561
I'm guessing you're worried about the distribution of mt_rand(). I have tested it and it is very level and both bounds are inclusive.
我猜你担心 mt_rand() 的分布。我已经测试过它,它非常水平,并且两个界限都包含在内。
I added my test to the comments of the documentation for mt_rand() on the php manual, but it was removed by a silly moderator due to politics that are too long winded to go into here.
我将我的测试添加到了 php 手册中 mt_rand() 文档的评论中,但由于太冗长,无法进入这里,它被一个愚蠢的版主删除了。
回答by diyism
use /dev/ramdom (linux device true random number generator) to seed mt_rand
使用 /dev/ramdom(linux 设备真随机数生成器)来播种 mt_rand
<?
$rnd_dev=mcrypt_create_iv(4, MCRYPT_DEV_RANDOM); //need "apt-get install php5-mcrypt"
$seed=ord(substr($rnd_dev, 0, 1))<<24 |
ord(substr($rnd_dev, 1, 1))<<16 |
ord(substr($rnd_dev, 2, 1))<<8 |
ord(substr($rnd_dev, 3, 1));
mt_srand($seed);
echo mt_rand();
?>
回答by Mark Rushakoff
If you don't like PHP's built in rand(), you probably shouldn't use their built-in shuffle()either, since it seems to be built on their rand().
如果您不喜欢 PHP 的内置rand(),您可能也不应该使用它们的内置shuffle(),因为它似乎是建立在他们的rand().
I am halfway sure the "industry standard" shuffle now is the Fisher-Yatesshuffle.
我有一半肯定现在的“行业标准”洗牌是费舍尔-耶茨洗牌。

