我如何安全地假设SHA1哈希的一部分是单一的?

时间:2011-03-22 08:55:58

标签: security sha1

我目前正在使用SHA1来缩短网址:

Digest::SHA1.hexdigest("salt-" + url)

仅使用SHA1的前8个字符作为唯一标识符是多么安全,就像GitHub明显提交的一样?

4 个答案:

答案 0 :(得分:11)

要计算具有给定长度的碰撞概率和您拥有的散列数,请参阅birthday problem。我不知道你将要拥有的哈希数量,但这里有一些例子。 8个十六进制字符是32位,因此对于大约100个哈希,碰撞的概率大约为1 / 1,000,000,对于10,000个哈希,它大约是1/100,对于100,000,它是3/4等。

请参阅维基百科上Birthday attack文章中的表格,找到满足您需求的良好哈希长度。例如,如果您希望碰撞的可能性低于1 / 1,000,000,000(对于超过100,000个哈希值的集合),则使用64位或16个十六进制数字。

这一切都取决于你将拥有多少哈希以及你愿意接受的碰撞概率(因为总有一些概率,即使非常小)。

答案 1 :(得分:7)

如果您正在谈论十六进制的SHA-1,那么每个字符只能获得4位,总共32位。碰撞的可能性与该最大值的平方根成反比,因此约为1/65536。如果您的URL缩短器被大量使用,那么在您开始发现冲突之前可能不会花费很长时间。

至于替代方案,最明显的可能只是维持一个反击。由于您需要存储URL表以将缩短的URL转换回原始URL,因此您基本上只需将每个新URL存储在表中。如果已经存在,则提供其现有编号。否则,您插入它并给它一个新的数字。无论哪种方式,您都可以将该号码提供给用户。

答案 2 :(得分:3)

这取决于你想要完成的任务。对于输入,SHA1的输出实际上是随机的(良好散列函数的输出根据输入中的一位变化改变其一半的位,而SHA1虽然不完美,但是相当不错),并且通过采用160位输出的32位(假设8个十六进制数字)子集,可以将输出空间从2 ^ 160减少到2 ^ 32个值。所有事情都是平等的,从来没有,这将大大降低发现碰撞的难度。

但是,如果散列函数的输入必须是有效的URL,则会显着减少可能的输入数量。 @rsp指出了生日问题,但鉴于此,我不确定它至少在其简单形式中是否具有适用性。此外,它主要假设没有其他预防措施。

我会更感兴趣的是你为什么要这样做。这是关于用户需要记住并键入的URL吗?如果是这样的话,加上一堆随机的十六进制数字可能是一个坏主意。它是一个只能以编程方式传递的URL或URL参数吗?然后,我不会太在乎长度。无论哪种方式,都可能有更好的方法来完成你想要完成的任务。

答案 3 :(得分:2)

如果对SHA1使用二进制输出并对结果进行Base64编码,则每个字符的信息密度会更高;您可以使用相同的8个字符的名称,但不仅仅是16^82^32)种可能性,您将拥有64^82^48)种可能性。

假设50%碰撞概率与1.177*sqrt(N)成比例,使用Base64风格编码将需要比十六进制输出多256倍的输入,然后才能达到50%的碰撞概率。