在 PHP 中生成随机密钥的最佳方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/637278/
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
What is the best way to generate a random key within PHP?
提问by Darryl Hein
I'm looking to create a reusable function that will generate a random key with printable ACSII characters of chosen length (anywhere from 2 to 1000+). I'm thinking printable ASCII characters would be 33-126. They key does not need to be completely unique, just unique if generated at the exact same millisecond (so uniqid()won't work).
我希望创建一个可重用的函数,该函数将生成一个随机密钥,该密钥具有选定长度的可打印 ACSII 字符(从 2 到 1000+ 的任意位置)。我认为可打印的 ASCII 字符是 33-126。它们的密钥不需要完全唯一,如果在完全相同的毫秒内生成则是唯一的(因此uniqid()不起作用)。
I'm thinking a combination of chr()and mt_rand()might work.
我想的组合chr()和mt_rand()可能的工作。
Is this the way to go, or is something else the best method?
这是要走的路,还是其他最好的方法?
Edit:uniqid()will also not work because it doesn't have a length parameter, it's just whatever PHP gives you.
编辑:uniqid()也不会工作,因为它没有长度参数,它只是 PHP 给你的。
My Idea: This is what I came up with:
我的想法:这就是我想出的:
function GenerateKey($length = 16) {
$key = '';
for($i = 0; $i < $length; $i ++) {
$key .= chr(mt_rand(33, 126));
}
return $key;
}
Are there any problems with this?
这有什么问题吗?
Another Edit:Most of the other questions deal with password generation. I want a wider variety of characters and I don't care about 1vs l. I want the maximum number of possible keys to be possible.
另一个编辑:大多数其他问题都涉及密码生成。我想要更多种类的角色,我不在乎1vs l。我希望尽可能多的可能的键成为可能。
Note: the generated key does not necessarily have to be cryptographically secure.
注意:生成的密钥不一定是加密安全的。
回答by St. John Johnson
Update (12/2015): For PHP 7.0, you should use random_int()instead of mt_randas it provides "cryptographically secure values"
更新 (12/2015):对于 PHP 7.0,您应该使用random_int()代替,mt_rand因为它提供了“加密安全值”
Personally, I like to use sha1(microtime(true).mt_rand(10000,90000))but you are looking for more of a customizable approach, so try this function (which is a modification to your request of this answer):
就个人而言,我喜欢使用sha1(microtime(true).mt_rand(10000,90000))但您正在寻找更多可定制的方法,因此请尝试使用此功能(这是对您对此答案的请求的修改):
function rand_char($length) {
$random = '';
for ($i = 0; $i < $length; $i++) {
$random .= chr(mt_rand(33, 126));
}
return $random;
}
Still, this will probably be significantly slower than uniqid(), md5(), or sha1().
尽管如此,这可能会比 uniqid()、md5() 或 sha1() 慢得多。
Edit:Looks like you got to it first, sorry. :D
编辑:看起来你是先到的,抱歉。:D
Edit 2:I decided to do a nice little test on my Debian machine with PHP 5 and eAccelerator (excuse the long code):
编辑 2:我决定用 PHP 5 和 eAccelerator 在我的 Debian 机器上做一个不错的小测试(原谅长代码):
function rand_char($length) {
$random = '';
for ($i = 0; $i < $length; $i++) {
$random .= chr(mt_rand(33, 126));
}
return $random;
}
function rand_sha1($length) {
$max = ceil($length / 40);
$random = '';
for ($i = 0; $i < $max; $i ++) {
$random .= sha1(microtime(true).mt_rand(10000,90000));
}
return substr($random, 0, $length);
}
function rand_md5($length) {
$max = ceil($length / 32);
$random = '';
for ($i = 0; $i < $max; $i ++) {
$random .= md5(microtime(true).mt_rand(10000,90000));
}
return substr($random, 0, $length);
}
$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
$temp = rand_char(1000);
echo "Rand:\t".(microtime(true) - $a)."\n";
$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
$temp = rand_sha1(1000);
echo "SHA-1:\t".(microtime(true) - $a)."\n";
$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
$temp = rand_md5(1000);
echo "MD5:\t".(microtime(true) - $a)."\n";
Results:
结果:
Rand: 2.09621596336
SHA-1: 0.611464977264
MD5: 0.618473052979
So my suggestion, if you want speed (but not full charset), is to stick to MD5, SHA-1, or Uniqid (which I didn't test.. yet)
所以我的建议,如果你想要速度(但不是完整的字符集),就是坚持使用 MD5、SHA-1 或 Uniqid(我还没有测试过……)
回答by SecurityJoe
None of the answers here are sufficient if you want cryptographic-strength randomness (is there a determined attacker trying to guess what your random keys are?). Hashing the time is not secure, an attacker can greatly speed up their search by guessing around the time they think your server generated the key, and it's easy to search over all milliseconds in a given year, even on a commodity laptop (it's a 35 bit search space). Also, the suggestion to just run the results of uniqid()or some other weak random source through a hash function to "expand it" is dangerous-this doesn't make an attacker's search harder once they find out that you did this.
如果您想要加密强度的随机性(是否有坚定的攻击者试图猜测您的随机密钥是什么?),这里的任何答案都不够。散列时间并不安全,攻击者可以通过猜测他们认为您的服务器生成密钥的时间来大大加快他们的搜索速度,并且即使在商用笔记本电脑上(这是一个 35位搜索空间)。此外,uniqid()通过散列函数运行或其他一些弱随机源的结果以“扩展它”的建议是危险的 - 一旦攻击者发现您这样做了,这不会使攻击者的搜索变得更加困难。
If you really need crypto-level security, you should read from /dev/random, the following code should work for you in any POSIX-compliant system (anything but Windows):
如果您确实需要加密级别的安全性,则应该从 /dev/random 中读取,以下代码应该适用于任何符合 POSIX 的系统(Windows 以外的任何系统):
#Generate a random key from /dev/random
function get_key($bit_length = 128){
$fp = @fopen('/dev/random','rb');
if ($fp !== FALSE) {
$key = substr(base64_encode(@fread($fp,($bit_length + 7) / 8)), 0, (($bit_length + 5) / 6) - 2);
@fclose($fp);
return $key;
}
return null;
}
If you need a bit more speed, you can read from 'dev/urandom' instead.
如果您需要更快的速度,可以改为从“dev/urandom”读取。
回答by Bob Somers
You can still use uniqid(), just do some additional processing to expand its value to the number of characters you need.
您仍然可以使用 uniqid(),只需进行一些额外的处理以将其值扩展到您需要的字符数。
For example, to expand it to 32 characters, you could do
例如,要将其扩展为 32 个字符,您可以这样做
$id = md5(uniqid());
To expand it to 64 characters, just append the md5 of the md5, like so
要将其扩展为 64 个字符,只需附加 md5 的 md5,就像这样
$first = md5(uniqid());
$id = $first . md5($first);
Then, trucate as necessary, if you need less than some multiple of 32.
然后,如果您需要少于 32 的某个倍数,则根据需要进行截断。
It's possible you could run into collisions, but it's pretty unlikely. If you're paranoid about that, just use the same idea, but chug uniqid()through a symmetric cipher like AES instead of hashing it.
您可能会遇到碰撞,但可能性很小。如果你对此感到偏执,只需使用相同的想法,但uniqid()通过像 AES 这样的对称密码而不是散列它。
回答by omar-ali
Why not use openssl_random_pseudo_bytes http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php
为什么不使用 openssl_random_pseudo_bytes http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php
回答by thomasrutter
My previous answer took a hash of uniqid() combined with a salt derived from system variables, but that doesn't generate a randomkey, only one that is highly likely to be unique. Similarly, the output from rand() or mt_rand() is not random enough for cryptographic purposes.
我之前的答案采用了 uniqid() 的散列和从系统变量派生的盐,但这不会生成随机密钥,只有一个很可能是唯一的。同样,rand() 或 mt_rand() 的输出对于加密目的来说不够随机。
To generate a random key, you need to go to a good random data source, and the function openssl_random_pseudo_bytes()is designed to do that:
要生成随机密钥,您需要找到一个好的随机数据源,而函数openssl_random_pseudo_bytes()就是为此而设计的:
$randkey = base64_encode(openssl_random_pseudo_bytes(32));
The base64_encode() is to make it into printable characters.
base64_encode() 是把它变成可打印的字符。
The reason the other answers don't recommend openssl_random_pseudo_bytes() is probably that it was introduced in PHP 5.3, and this question is nearly 6 years old.
其他答案不推荐 openssl_random_pseudo_bytes() 的原因可能是它是在 PHP 5.3 中引入的,这个问题已经有将近 6 年的历史了。
回答by user266926
$key = md5(microtime() . rand());
$key = md5(microtime() .rand());
Microtime by itself isn't safe because it leaves only 1/1000 chance of being guessed.
Microtime 本身并不安全,因为它只留下 1/1000 被猜测的机会。
Rand by itself is also not very secure, but hashing their concatenating them together yields a pretty solid randomization.
Rand 本身也不是很安全,但是将它们连接在一起散列在一起会产生非常可靠的随机化。
回答by lpfavreau
Does that questionwould be of interest to you?
你会对这个问题感兴趣吗?
I'm not sure why uniqid()doesn't work for you and in what case you need a unique number in the same millisecond but not necessarily otherwise; what are you generating so fast that in the same millisecond you could have a collision? I'm wondering how much time does uniqid()takes just to generate its number. If you want, use the prefix parameter of the uniqid()function with a few random letters and you should be safe.
我不确定为什么uniqid()对你不起作用,在什么情况下你需要在同一毫秒内有一个唯一的数字,但不一定是其他情况;你生成的什么东西如此之快,以至于在同一毫秒内你可能会发生碰撞?我想知道uniqid()生成它的数字需要多少时间。如果需要,请使用uniqid()带有几个随机字母的函数的前缀参数,您应该是安全的。
If it's for generating file, you might want to look at tmpfile()or tempname().
如果是用于生成文件,您可能需要查看tmpfile()或tempname()。
In any case, depending on what you are trying to achieve, you can just loop and verify if the unique id is already taken (in an array, with file_exists, etc.) and just generate another one if it's the case.
在任何情况下,根据您要实现的目标,您可以循环并验证是否已经使用了唯一 id(在数组中,使用 file_exists 等),如果是这种情况,则只需生成另一个。
Also, as I'm not sure I understand your question exactly, I would point you to those other questions that sound pretty similar while I get the difference of yours:
另外,由于我不确定我是否完全理解您的问题,因此我会向您指出其他听起来非常相似的问题,而我却得到了您的不同之处:
- Generating (pseudo)random alpha-numeric strings
- How many random elements before MD5 produces collisions?
The first one will be of interest if you are looking to do a unique id that's human readable. The second one could be useful if you want to play with random numbers and md5/sha1. Although, again, I think uniqid()might already be what you are looking for.
如果您想要做一个人类可读的唯一 id,第一个会很有趣。如果你想玩随机数和 md5/sha1,第二个可能很有用。虽然,我认为uniqid()可能已经是你正在寻找的。
回答by Ahmet ATAK
Also you can generate a random key and check the key in your DB if the key is exits, you can generate another key by this method
您也可以生成一个随机密钥并检查数据库中的密钥,如果密钥存在,您可以通过此方法生成另一个密钥
function activation($lengt=20){
$modalpage =new Modal;//you can call your modal page and check the key
$characters = "1234567890abcdefghijklmnopqrstuvwxyz";
for($i=0;$i<$lengt;$i++)
{
$key .= $characters{rand(0,35)};
$check= array(
":key" => $key,
);
$result = $modalpage->findkey($check);
if($result==true){ //if the key is exits return the function and generate another key !
return activation($lengt);
}else //if the key is not exits return the key
return $key;
}
}
$mykey=activation(15);

