独特的密钥生成

时间:2020-03-05 18:51:03  来源:igfitidea点击:

我正在寻找一种方法,特别是在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,但不确定这些键是否完全唯一。

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

解决方案

回答

如果不编写代码,我的逻辑将是:

根据我们喜欢的任何可接受的字符生成一个随机字符串。
然后,将日期戳的一半(部分秒数和全部)添加到前面,将另一半添加到末尾(如果需要,则添加在中间的某个位置)。

保持快乐!
H

回答

如果我们使用原始方法,但在密码前面添加了用户名或者电子邮件地址,则每个用户只能拥有1个密码,则该名称将始终是唯一的。

回答

我们可能对处理相同问题的本文感兴趣:GUID在全球范围内是唯一的,但GUID的子字符串不是。

The goal of this algorithm is to use the combination of time and location ("space-time coordinates" for the relativity geeks out there) as the uniqueness key. However, timekeeping is not perfect, so there's a possibility that, for example, two GUIDs are generated in rapid succession from the same machine, so close to each other in time that the timestamp would be the same. That's where the uniquifier comes in.

回答

我通常这样做:

$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));
}

我想有一些理论上的漏洞,但是我从来没有遇到过重复问题。我通常将其用于临时密码(例如在重置密码后),并且足够有效。

回答

我通常会做一个随机的子字符串(为方便起见,随机分配8至32之间的几个字符)或者我得到的某个值的MD5,时间或者某种组合。为了获得更大的随机性,我将值(假设为姓)的MD5与时间连接起来,再次将MD5与时间连接起来,然后采用随机子字符串。是的,我们可以获得相同的密码,但是不太可能。

回答

我们可能对史蒂夫·吉布森(Steve Gibson)的密码生成器的顶级安全实现感兴趣(无来源,但他对密码生成器的工作方式有详细说明),网址为https://www.grc.com/passwords.htm。

该站点创建了庞大的64个字符的密码,但是由于它们是完全随机的,因此我们可以轻松获取前8个(或者多个)字符,以获得不太安全但"尽可能随机"的密码。

编辑:从我们以后的答案中,我看到我们需要的是GUID而不是密码,所以这可能不是我们想要的...

回答

任何算法都将导致重复。

因此,我是否建议我们使用现有算法*并仅检查重复项?

*稍微增加一点:如果uniqid()在时间上可能是不唯一的,则还应包含一个全局计数器,我们在每次调用后都会增加它。这样一来,即使在相同的微秒内,情况也会有所不同。

回答

正如Frank Kreuger所评论的,请使用GUID生成器。

像这个

回答

我仍然看不到为什么密码必须唯一?如果两个用户使用相同的密码,会有什么弊端?

这是假设我们在谈论的是与用户ID关联的密码,而不仅仅是唯一的标识符。如果这就是我们要寻找的,为什么不使用GUID?

回答

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

  • 使用有效的GUID生成器-这些生成器很长且不能缩小。如果仅使用零件,则将失败。
  • 该数目的至少一部分是根据单个序列顺序生成的。我们可以添加绒毛或者编码,以减少顺序感。优点是它们起步短-缺点是它们需要单一来源。单一来源限制的解决方法是为来源编号,因此我们要包含[source#] + [seq#],然后每个来源都可以生成自己的序列。
  • 通过其他方式生成它们,然后对照先前生成的值的单个历史记录对其进行检查。

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

关于GUIDS的注意事项:它们从其长度和生成它们的方法中获得了独特的优势。少于128位的任何内容都是不安全的。除了随机数生成之外,GUID还具有一些特性,可以使其变得更加独特。请记住,它们实际上几乎是唯一的,而不是完全唯一的。有可能,尽管实际上没有重复的可能性。

关于GUIDS的更新注释:自撰写本文以来,我了解到许多GUID生成器都使用加密安全的随机数生成器(很难或者不可能预测生成的下一个数字,并且不太可能重复)。实际上有5种不同的UUID算法。 Microsoft当前用于Windows GUID生成API的是算法4. GUID是Microsoft对UUID标准的实现。

更新:如果需要7至16个字符,则需要使用方法2或者3.

底线:坦率地说,没有完全独特的东西。即使我们使用顺序生成器,我们最终也将耗尽整个宇宙中所有原子的存储空间,从而循环回到自己身上并重复执行。我们唯一的希望是在达到该点之前宇宙的热死。

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

因此,这一切都取决于独特性门槛。通过使用序列,然后对它进行base32编码,可以为1,099,511,627,776个数字的8位数字提供100%的唯一性。不涉及检查过去数字列表的任何其他方法仅具有不唯一的赔率,等于n / 1,099,511,627,776(其中n =生成的先前数字的数量)。

回答

我确实相信问题的一部分在于,我们正在尝试为我们提供一个单独的函数,用于两种单独的用途...密码和transaction_id

这确实是两个不同的问题领域,实际上最好不要一起解决它们。

回答

我最近想要一个快速简单的随机唯一键,所以我做了以下工作:

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

因此,基本上,我得到以秒为单位的Unix时间,并添加一个由时间+随机数生成的随机md5字符串。它不是最好的,但是对于低频请求来说,这是相当不错的。快速且有效。

我进行了一个测试,在该测试中,我将生成数千个密钥,然后查找重复项,并且每秒大约有800个密钥,没有重复项,所以还不错。我猜这完全取决于mt_rand()

我将其用于调查跟踪器,在该跟踪器中,每分钟大约有1000项调查的提交速度...因此,现在(交叉手指)没有重复项。当然,费率不是恒定的(我们会在一天中的某些时间获取提交信息),因此这并不是故障证明,也不是最佳的解决方案……提示是将增量值用作键的一部分(在我的情况下,我使用了time(),但可能会更好)。

回答

通常将与创建唯一值没有太大关系的加密部分进行加密,我通常使用这一部分:

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

在同一过程中调用$ counter时,其值将增加,因此在同一过程中值始终是唯一的。

当在不同的进程中调用时,我们一定真的很不幸获得2个具有相同值的microtime()调用,认为在同一脚本中调用microtime()调用通常也具有不同的值。