使用哈希作为唯一ID是错误的吗?


Is it wrong to use a hash for a unique ID?

我想在一个可能永远不会超过10,000条记录的数据库表中使用PHP生成的唯一ID。我不希望创建时间是可见的,也不希望使用纯数字值,所以我使用:

sha1(uniqid(mt_rand(), true))

是错误的使用哈希唯一的ID?不是所有的哈希都导致碰撞吗?还是这种可能性很小,不应该在这种情况下考虑它们?

还有一点:如果要散列的字符数小于sha1散列中的字符数,它不总是唯一的吗?

如果你有两个密钥,理论上最好的情况是1/2 ^ X的碰撞概率,其中X是哈希算法中的位数。'最佳情况',因为输入通常是ASCII,不利用完整的字符集,加上哈希函数不完美地分布,所以它们在现实生活中会比理论最大值更频繁地碰撞。

回答你的最后一个问题:

还有一点:如果要散列的字符数小于sha1散列中的字符数,不是总是唯一的吗?

是的,那是真的。但是生成这么大的唯一键会有另一个问题。最简单的方法通常是校验和,所以只要选择一个足够大的摘要,使碰撞空间足够小就可以了。

正如@wayne所建议的,一种流行的方法是将microtime()连接到您的随机盐(和base64_encode以提高熵)。

如果两个结果相同该有多可怕?墨菲定律适用——如果一百万分之一,甚至十万:一的概率是可以接受的,那就勇往直前吧!真正的机会要小得多——但如果你的系统在这种情况下会爆炸,那么你必须首先解决你的设计缺陷。然后自信地继续。

这是一个关于概率的问题/答案:SHA1碰撞的概率

使用sha1(time())代替,那么只要时间可以表示为比sha1哈希短,就可以消除重复哈希的随机可能性。(可能比找到一个工作的PHP解析器还要长;))

电脑随机其实不是随机的,你知道吗?假设您在Unix环境中,您可以从计算机获得的唯一真正的随机是/dev/random,但这是一个依赖于用户交互(如移动鼠标或在键盘上键入)的阻塞操作。从/dev/urandom读取是不太安全的,但它可能是更好的东西,只使用ASCII字符,并给你即时响应。

sha1($ipAddress.time())因为任何人都不可能在同一时间使用相同的IP地址