我在使用 PHP 的网站上编写了一些代码来创建一个随机散列值 (使用sha1()
),并将其用于匹配数据库中的记录。
这种情况发生碰撞的几率是多少?我应该先生成哈希值,然后检查它是否在数据库中(我宁愿避免额外的查询),还是根据它与其他数据发生碰撞的概率自动插入记录。
我在使用 PHP 的网站上编写了一些代码来创建一个随机散列值 (使用sha1()
),并将其用于匹配数据库中的记录。
这种情况发生碰撞的几率是多少?我应该先生成哈希值,然后检查它是否在数据库中(我宁愿避免额外的查询),还是根据它与其他数据发生碰撞的概率自动插入记录。
使用对称加密方案和私有服务器密钥对ID(以及其他值)进行加密,然后在收到时解密。要注意,您的加密函数应同时提供机密性和完整性检查。
这使您可以在与数据库通信时使用合理的值而不会产生任何冲突,在与客户端通信时提供更高的安全性,并将您降落在thedailyWTF的概率减少了2^160次方左右。
为什么不做一些能够保证没有冲突的事情,同时确保没有人可以更改GET参数来查看他们不应该查看的内容:使用盐值,将ID和其哈希组合在一起。
$salt = "salty";
$key = sha1($salt . $id) . "-" . $id;
// 0c9ab85f8f9670a5ef2ac76beae296f47427a60a-5
即使您意外地遇到两个具有相同SHA1哈希(使用您的盐)的数字,那么$key仍将不同,您将避免所有冲突。
SHA-1生成160位长的摘要。因此,只要你的条目少于2^(160/2),你就是安全的。除以2是由于生日悖论。
从最基本的原理来说:
SHA-1可以生成一个160位的摘要。假设它平均使用了整个比特空间(这应该是它设计时的考虑),每次插入的碰撞概率只有2^-160。
因此,对于每个插入操作,我们可以安全地假设没有碰撞,并在出现碰撞时处理错误。
但这并不意味着你可以完全忽略碰撞的可能性。
生日悖论表明,在你的数据库中至少有一次碰撞的机会比你想象的要高,因为有O(N^2)种可能的碰撞。
有一个非常简单的规则可以找出任何哈希算法是否会发生冲突。 如果算法的输出范围是有限的数字,迟早会发生冲突。
尽管SHA1具有2^160个哈希可能性的非常大的范围,但它仍然是有限的数字。然而,可以传递给该函数的输入实际上是无限的。在足够大的输入数据集中,必定会发生冲突。
问一下如果发生碰撞会花费多少钱。如果这是一个免费的网站那就没问题了。但如果你经营的是赚钱的业务,而覆盖将使你失去一份价值百万美元的合同,那么我认为你需要重新考虑。
我认为你的方法不对。
我认为你需要保留唯一标识符,但要确保用户无法手动更改该标识符。
一种方法是将ID和ID的哈希值(加上一些额外数据)放在链接中。
例如:(我的PHP有点生疏,所以以下是通用算法:)
id = 5;
hash = hash("My Private String " + id)
link = "http://mySite.com/resource?id=" + id + "&hash=" + hash
那么当你收到请求时,只需验证您可以根据ID重新生成哈希。这确实让您容易受到攻击,以找出"My Private String",但这将是相当计算困难的,您可以始终附加其他不直接向用户公开的唯一内容(例如会话ID)。
其他评论已经涵盖了概率问题,但是如果你从实际角度来看待这个问题,你可以为自己得到一个明确的答案。
你自己说过,你将要对连续的ID进行哈希。编写一个测试用例很容易。迭代 ~100,000,000 个 ID 并检查碰撞。这不需要太长时间。另一方面,你可能会在四分之一的时候就耗尽内存。