2008-09-10 158 views
12

我正在寻找一种方式,特别是在PHP中,我将保证始终获得唯一的密钥。唯一密钥生成

我也做了以下内容:

strtolower(substr(crypt(time()), 0, 7)); 

但我发现,一旦在一段时间我结束了重复的密钥(很少,但往往不够)。

我也想过这样做的:

strtolower(substr(crypt(uniqid(rand(), true)), 0, 7)); 

但根据PHP的网站,uniqid()可以,如果uniqid()在同一个微秒的叫了两声,就可能产生相同的密钥。我正在考虑添加rand(),它很少会这样做,但仍然有可能。

在上面提到的行之后,我还删除了L和O等字符,这样对用户来说就不那么令人困惑了。这可能是重复原因的一部分,但仍然是必要的。

我想到的一个选择是创建一个网站,该网站将生成密钥,将其存储在数据库中,确保它完全独一无二。

还有其他想法吗?是否有任何网站已经做到了这一点,有一些API或只是返回密钥。我发现http://userident.com,但我不确定密钥是否完全独特。

这需要在没有任何用户输入的情况下在后台运行。

+0

为什么密码需要完全独特? – 2008-09-10 20:24:52

+0

我想crypt只是因为你需要crypt值,它与创建独特的价值无关,不是吗?! – 2010-03-18 19:22:51

+0

另请参阅:[用于生成v4 UUID的PHP函数](http://stackoverflow.com/a/15875555/1338292)。 – 2014-11-25 03:12:37

回答

19

只有3种方式来生成唯一值,而它们是密码,用户ID等:

  1. 使用有效GUID发电机 - 这些都是长期不能被压缩。如果您只使用零件您失败
  2. 至少部分数字是从单个序列中顺序生成的。您可以添加绒毛或编码,使其看起来不那么顺序。优点是他们开始短 - 缺点是他们需要一个单一的来源。解决单一来源限制的方法是编号来源,因此您可以包含[source#] + [seq#],然后每个来源都可以生成自己的序列。
  3. 通过其他方式生成它们,然后根据以前生成的值的单个历史记录来检查它们。

的任何其他方法不能保证。请记住,从根本上说,您正在生成一个二进制数(它是一台计算机),但您可以使用十六进制,十进制,Base64或单词列表对其进行编码。选择适合您使用情况的编码。通常对于用户输入的数据,你需要一些Base32的变体(你暗示的)。

关于GUIDS的注意事项:他们从长度和生成它们的方法中获得了独特的力量。 小于128位的任何内容都不安全。除了随机数生成之外,还有一些特性会进入GUID以使其更加独特。请记住,它们实际上是独一无二的,而不是完全独特的。有可能,尽管实际上不可能有重复。由于编写本文,我了解到许多GUID生成器使用密码安全的随机数生成器(难以或不可能预测下一个生成的数字,而且不太可能重复)。实际上有5种不同的UUID algorithms。算法4是Microsoft当前用于Windows GUID生成API的内容。 A GUID是Microsoft对UUID标准的实现。

更新:如果要7到16个字符,那么你需要使用这两种方法2或3

底线:坦率地说,没有这样的事情完全是独一无二的。即使你使用顺序发生器,你最终也会用到宇宙中所有原子的存储空间,从而重复循环。你唯一的希望就是在达到那个点之前宇宙的热死亡。

即使是最好的随机数生成具有重复等于要生成的随机数的总大小的可能性。以四分之一为例。它是一个完全随机的位发生器,其重复的几率是1中的2.

所以这一切都归结到你的唯一性的门槛。通过使用一个序列,然后使用base32编码,您可以在1,099,511,627,776个数字的8位数字中具有100%的唯一性。不涉及检查过去数字列表的任何其他方法的赔率等于n/1,099,511,627,776(其中n =生成的先前数字的数目)不是唯一的。

0

无需编写代码,我的逻辑是:

生成任何可接受的字符,你喜欢一个随机字符串。
然后将一半的日期戳(部分秒和全部)加到前面,另一半加到结尾(或者如果你喜欢的话,在中间的某个地方)。

保持JOLLY!
H

+1

这很接近,但取决于你的随机程序只有微秒的精度。正如他所说,uniqid因相同的可能性而失败。 – 2008-09-10 21:28:42

0

如果您使用原始方法,但在密码前添加用户名或电子邮件地址,它将永远是唯一的,如果每个用户只能有1个密码。

0

您可能会对这篇文章感兴趣,它涉及相同的问题:GUIDs are globally unique, but substrings of GUIDs aren't

该算法的目标是使用的时间和位置的组合(“时空坐标”为相对论爱好者那里)作为唯一关键。但是,计时并不完美,因此有可能例如从同一台计算机快速连续生成两个GUID,这样在时间上彼此接近,以便时间戳相同。这其中唯一标志进来

0

我通常做的是这样的:

$this->password = ''; 

for($i=0; $i<10; $i++) 
{ 
    if($i%2 == 0) 
     $this->password .= chr(rand(65,90)); 
    if($i%3 == 0) 
     $this->password .= chr(rand(97,122)); 
    if($i%4 == 0) 
     $this->password .= chr(rand(48,57)); 
} 

我想有一些理论洞,但我从来没有与重复的问题。我通常使用它作为临时密码(就像在密码重置后),它的工作原理就足够了。

-1

我通常做的随机串(随机如何8的32或更小之间的许多字符为方便用户)或一些值我已经得到在的MD5,或时间,或其某些组合。对于更多的随机性,我将MD5的值(比如姓氏)与时间MD5连接起来,然后取出随机的子串。是的,你可能获得相同的密码,但它不是很可能。

+0

如果您采用加密安全散列的子字符串,则可以打破散列的唯一性。散列的任何部分都不比其他任何部分更安全或随机。使用普通的随机数发生器调用密码的可能性相同。 – 2008-09-10 21:35:18

0

您可能感兴趣的是Steve Gibson在https://www.grc.com/passwords.htm处的密码生成器的过度安全实现(没有源代码,但他详细描述了它的工作原理)。

该网站创造了巨大的64个字符的密码,但是,因为他们是完全随机的,你可以很容易地取前8(或然而,许多)字符的安全性较低,但“尽可能的随机口令”。

编辑:从你后来的回答我看你需要的东西更像是一个GUID比一个密码,所以这可能不是你想要的...

1

任何算法将导致重复

因此,我可能会建议您使用现有的算法*,只是重复检查? *轻微加法:如果uniqid()可以基于时间是非唯一的,还包括一个全局计数器,您在每次调用后增加一个全局计数器。即使在相同的微秒,这种方式也是不同的。

+0

GUID(或UUIDS)和序列是避免重复的唯一两种方法,但对于此处提及的每种其他算法,您都是正确的。 – 2008-09-10 21:36:28

+0

如果允许任意标识符长度,我同意。如果他想像他的例子那样保持8个字符,那仅仅是不够的。 – 2008-09-10 21:59:58

0

弗兰克Kreuger评论,去与一个GUID发电机。

this one

0

我仍然没有看到为什么密码必须是唯一的?如果您的两位用户拥有相同的密码,那么缺点如何?

这是假设我们谈论到绑定用户ID,并不仅仅是唯一标识符的密码。如果那是你在找什么,为什么不使用GUID?

0

我相信您的问题的一部分是,你想给我们一个单一功能的两个独立的用途......密码和TRANSACTION_ID

这确实是两个不同的问题领域,它真的不是最好尝试一起解决它们。

0

我最近想快速和简单随机的唯一关键,所以我做了以下内容:

$ukey = dechex(time()) . crypt(time() . md5(microtime() + mt_rand(0, 100000))); 

所以,基本上,我得到的UNIX时间以秒计,并添加从时间+随机数生成一个随机的MD5串。这不是最好的,但对于低频率的请求,它是非常好的。它速度快,工作。

我做了一个测试,在那里我会生成数千个密钥,然后查找重复数据,并且每秒钟有大约800个密钥没有重复,所以也不错。我想这完全取决于mt_rand()

我用它的调查跟踪我们得到每分钟约1000调查的提交速度...所以现在(交叉手指)有没有重复。当然,这个比率并不是恒定的(我们在一天的特定时间得到提交),所以这不是失败证明,也不是最好的解决方案......提示是使用增量值作为密钥的一部分(在我的情况中,我用时间(),但可能会更好)。

0

Ingoring不会有太大与创造独特的价值做我通常使用这一个crypting部分:

function GetUniqueValue() 
{ 
    static $counter = 0; //initalized only 1st time function is called 
    return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++; 
} 

当在同一进程$计数器称为增加,从而值始终在同一个进程独特。

当在不同的工艺叫你一定很倒霉拿到2 microtime中()具有相同价值观打电话,认为microtime中()调用通常有不同的价值观在同一脚本调用也时。