【问题标题】:Hash map keys are not random哈希映射键不是随机的
【发布时间】:2015-05-13 22:11:31
【问题描述】:

似乎 Java 的 HashMap 实现 总是 将键放置在相同的 bin 中(至少我在整数键中看到了这一点)。 IE。散列是确定性的,在所有运行中它产生相同的值。
我听说某些语言会随机插入,因此出于安全原因,密钥将存储在哪个存储桶中是不可预测的。
为什么 Java 的键总是一样的?

【问题讨论】:

  • 大概是因为 HashMap 没有针对安全性进行优化? (FWIW,我对桶随机化如何提高安全性很感兴趣。)
  • @OliverCharlesworth:我不知道任何 Web 应用程序使用的 java 的另一种 hashmap 实现(仅出于性能原因不同)
  • @OliverCharlesworth:所以不应该所有的哈希图都是随机的吗?
  • @OliverCharlesworth 它可以防止某些类别的 DoS 攻击;如果攻击者可以为您提供所有哈希到同一个存储桶的密钥,那么他们可以使您的代码运行缓慢。
  • 我不会为此使用HashMap,它不是为此目的而创建的... ¿为什么不随机创建密钥?出于您的安全原因,哈希将是可以的...

标签: java security hash collections hashmap


【解决方案1】:

这里感兴趣的攻击是拒绝服务 (DoS)。攻击者选择一组击中同一个桶的键。这将映射操作的性能从 O(1) 转换为 O(n)。这样做 n 次(比如构建地图),我们从 O(n) 到 O(n^2)。还有时间攻击的可能性,但我会很方便地忽略它。

一般来说,大多数库代码会假定无需采取任何措施来避免 DoS。然而,最近一些 Java 实现已经使用 MURMUR 散列来随机化 String 的散列函数以避免某些攻击。 MURMUR 将每个进程的随机数混合到哈希码的生成中,这样函数对于进程来说是稳定的,但很难(尽管不一定不可能)从外部弄清楚。最近,如果存在过多的冲突并且密钥适当地实现了Comparable,则这已被替换为回退到树结构。

如果您在找到您的代码的情况下担心此类攻击,您可以使用其他Map 实现,例如java.util.TreeMap

【讨论】:

  • 我不明白TreeMap 在这种情况下如何更好?这种漏洞对于商业级应用程序来说也是微不足道的吗?
  • @Jim:TreeMap 已经保证了 O(log(n)) 的性能,无论提供什么输入,所以不能仅仅通过提供特定的一组来强制它进入 O(n) 的性能最坏情况值。
  • A TreeMap 将始终在 O(log n) 时间内执行常见的 Map 操作,因为如果键选择尝试强制使用不稳定的结构,它将重新平衡。在正常操作中速度不那么快,但在最坏的情况下会好得多。
  • 也就是说,在 Java 的当前版本中,如果单个桶中有太多冲突(并且如果键是可比较的),HashMap 将回退到平衡二叉搜索树。所以现在可能不需要使用TreeMap
【解决方案2】:

这不适用于 Java 7,它为每个 HashMap 实例添加了唯一的哈希种子。在Collections Framework Enhancements in Java SE 7 页面上有更多信息。

为了提高性能,Java 8 中删除了该机制,取而代之的是一种将可比较的键(如字符串)转换为平衡树以消除 DoS 安全问题的替代方案。在Collections Framework Enhancements in Java SE 8 页面上有更多信息。

【讨论】:

  • 这是“为什么...?”问题的正确答案
【解决方案3】:

在 Java 中,单个类负责实现默认的 hashCode() 方法(或从 Object 类继承一个),而像击败高级 DoS 攻击这样的复杂安全场景不是 Object 等类的责任、Integer

因此,大多数类都使用一种非常简单、快速的实现方式,试图确保在常见情况下的分布相当均匀。

如果您觉得实施自定义哈希策略很重要,无论是因为您想避免黑客攻击,还是因为您知道您的特定用法可能会导致与默认方法发生大量冲突,您可以使用像Gnu Trove'sTHashMap 这样的集合,它允许您提供特定于集合实例的自定义散列策略。

【讨论】:

  • hashCode 总是为一个对象返回相同的数字,它必须这样做。实现如何决定如何使用 hashCode 使其落入或不会落入同一个桶,这是哈希表实现的问题,而不是对象的问题
  • @Jim:同意。 hashCode 还应该做出合理的努力来避免不同的值也产生相同的哈希值,甚至不同的哈希值可能落入同一个桶中。但在某些时候,我们需要认识到,每个单独的类都不能负责产生一个可靠的、不可猜测的哈希函数。
  • Trove 肯定不是现在应该被称为“Java 的自定义数据结构”的单个项目。见java-performance.info/…。从任何角度来看,本文中提到的所有项目都优于 Trove。 (并且它们都允许提供自定义散列策略。)
  • 此外,Trove 项目名称导致了这是 GNU 项目的谬误。实际上它只是使用 (L?)GPL 许可证,这是唯一连接项目和 GNU 组织的东西。
  • @leventov:感谢您的反馈。我从来没有理由使用这些。 Trove 只是第一个出现在我的 Google 搜索中的人。
【解决方案4】:

要完成其他答案,我会提到当HashMap 的键使用内置Object.hashCode 时,i。 e.不要覆盖此方法,这是很常见的情况,Object 的 hashCode 是使用随机数生成器计算的,这使得整个系统的行为不太确定。有关详细信息,请参阅此问题:Java Object.hashCode() - address or random()?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 2015-09-08
    • 1970-01-01
    • 2014-06-19
    相关资源
    最近更新 更多