使用哈希作为唯一 ID 是错误的吗?
Posted
技术标签:
【中文标题】使用哈希作为唯一 ID 是错误的吗?【英文标题】:Is it wrong to use a hash for a unique ID? 【发布时间】:2013-04-27 11:03:58 【问题描述】:我想在可能永远不会超过 10,000 条记录的数据库表中使用 php 生成的唯一 ID。我不希望创建时间可见或使用纯数值,所以我正在使用:
sha1(uniqid(mt_rand(), true))
对唯一 ID 使用哈希是错误的吗?不是所有的哈希都会导致冲突吗?或者在这种情况下不应该考虑这些可能性?
还有一点:如果要散列的字符数小于 sha1 散列中的字符数,它不总是唯一的吗?
【问题讨论】:
不,没有错。使用将时间戳传递给 sha1 会很好。 这可能是个好读物:: ***.com/questions/2768191/… 为什么要创建自己的唯一 ID?你的数据库不支持自增主键吗?这通常被认为是在数据库标识符上拥有唯一 ID 的方式。 @Patrick M 我不希望这些 ID 有任何意义。 这样做的一个原因是为了防止黑客在您的应用程序中找到一个 http GET 端点,并简单地使用这些顺序自动递增的键来浏览您的数据库。几年前发生在 AT&T 上的事情相当有名,抱歉,找不到它的链接,但我每次设计系统时都会记得它。因此,将端点 /customer/5 转换为 /customer/dhftrt5sahjgertgjwygad 是一个明显的优势 - 否则会真的如此简单地被黑客入侵。 【参考方案1】:如果您有 2 个密钥,理论上最好的情况是 2 中 1 ^ X 的冲突概率,其中 X 是您的哈希算法中的位数。 “最佳情况”,因为输入通常是不使用完整字符集的 ASCII,加上散列函数分布不完美,因此它们会比现实生活中的理论最大值更频繁地发生冲突。
回答你的最后一个问题:
还有一点:如果要散列的字符数小于 sha1 哈希中的字符数,它不总是唯一的吗?
是的,没错。但是您会遇到另一个问题,即生成该大小的唯一键。最简单的方法通常是校验和,因此只需选择一个足够大的摘要,以使碰撞空间足够小,让您感到舒适。
正如@wayne 建议的那样,一种流行的方法是将microtime()
连接到您的随机盐(和base64_encode
以提高熵)。
【讨论】:
谢谢,应该是:sha1(base64_encode(microtime().uniqid(mt_rand(), true))) @texelate 这将是一个很好的起点。有关盐渍的更多信息,请参阅此页面点,尤其是 1+2:blog.ircmaxell.com/2012/12/seven-ways-to-screw-up-bcrypt.html 谢谢。我需要它是为了唯一性而不是安全性,但仍然是非常有用的阅读。【参考方案2】:如果两个结局相同,那该有多可怕?墨菲定律适用 - 如果一百万比一,甚至 100,000:1 的机会是可以接受的,那就继续吧!真正的机会要小得多——但如果发生这种情况你的系统会爆炸,那么必须首先解决你的设计缺陷。然后充满信心地继续前进。
以下是关于概率的真正含义的问题/答案:Probability of SHA1 Collisions
【讨论】:
【参考方案3】:使用 sha1(time()) 代替,然后您消除重复哈希的随机可能性,只要时间可以表示为比 sha1 哈希更短。 (可能比你找到一个工作的 php 解析器要长;))
【讨论】:
then you remove the random possibility of a repeating hash
.. 除非您实例化超过 1 个对象 pr。第二 - 恕我直言,这不是很多。我建议不要只使用时间戳作为唯一键的输入【参考方案4】:
计算机随机实际上并不是随机的,你知道吗?
假设您在 Unix 环境中,您可以从计算机获得的唯一真正随机来自 /dev/random
,但这是一个阻塞操作,取决于用户交互,例如移动鼠标或在键盘上打字。从/dev/urandom
读取不太安全,但它可能比仅使用 ASCII 字符更好,并且可以立即响应。
【讨论】:
【参考方案5】:sha1($ipAddress.time()) 导致任何人不可能同时使用相同的IP地址
【讨论】:
以上是关于使用哈希作为唯一 ID 是错误的吗?的主要内容,如果未能解决你的问题,请参考以下文章
什么是密钥哈希?为什么需要它?它是唯一的吗?为什么 Facebook 集成需要它