【问题标题】:Why is std::hash not guaranteed to be deterministic?为什么 std::hash 不能保证是确定性的?
【发布时间】:2020-06-19 10:20:34
【问题描述】:

此后,我们使用N4140(C++14 标准)。


根据§ 17.6.3.4 哈希要求

返回的值应仅取决于参数k 在项目期间

[ 注意:因此,表达式h(k) 的所有计算都具有相同的值 k对于给定的程序执行产生相同的结果。 ——尾注]

§20.9.12 类模板哈希

...

实例化hash<Key> 应:

(1.1) — 满足哈希要求 (17.6.3.4) ...

(1.2) — ...


这意味着如果您重新启动程序,value(即hash<decltype(value)>(value))的哈希值可能会采用不同的值。

但是为什么呢?此限制不在 C++11 标准中,而是在 C++14、C++17 和 C++20 标准中。作为用户(不是 STL 开发人员),如果 std::hash 是确定性的,那将非常有用。实现确定性哈希函数是否有任何数学困难?但是我们日常使用的散列函数(例如已弃用的md5sum 或更安全的sha256)都是确定性的。效率有问题吗?

【问题讨论】:

  • "...哈希函数只需要在程序的单次执行中为相同的输入产生相同的结果;这允许防止冲突拒绝的加盐哈希-服务攻击。”来源:en.cppreference.com/w/cpp/utility/hash
  • 它允许确定性算法采用非确定性输入。例如,指针值。不可变的数据结构可以散列其内部数据的地址,这可能比散列内容快得多。
  • This answer 提供了一些很好的链接,说明您为什么不想要确定性。
  • 不要威胁这是限制,而是让标准约束不那么严格。
  • 这里是full explanation why 约束已经放宽了。

标签: c++ hash language-lawyer std


【解决方案1】:

哈希函数不需要在运行之间具有确定性,但您仍然可以提供自己的哈希,例如如果这是您依赖的行为,则适用于无序容器。

至于为什么,cppreference 说:

哈希函数只需要在程序的单次执行中为相同的输入产生相同的结果;这允许防止冲突拒绝服务攻击的加盐哈希。

如果Hash 要求告诉它是确定性的,那么您将无法在不违反要求的情况下提供加盐哈希。

这里是actual explanation why

【讨论】:

    【解决方案2】:

    @NathanOliver 建议的This answer(以及其中的链接)最终会有所帮助。让我引用重要的部分。

    对于非加密哈希函数,可以预先计算具有相同哈希值的大量输入,以通过算法减慢无序容器的速度,并导致拒绝服务攻击。

    (来自Issue 2291. std::hash is vulnerable to collision DoS attack

    出于这个原因,语言设计者正在迁移到随机散列。在随机散列中,每次运行程序时,字符串“a”的散列值都会发生变化。随机散列现在是 Python(从 3.3 版开始)、Ruby(从 1.9 版开始)和 Perl(从 5.18 版开始)的默认设置。

    (来自Do you realize that you are using random hashing?

    移动到就绪,而不是立即,因为在反射器讨论中即使是许可也存在争议

    (来自Issue 2291. std::hash is vulnerable to collision DoS attack

    在实践中,据我所知,std::hash 的实现没有实现随机散列,但您可以编写自己的 my::secure_hash

    (来自this answer


    附言

    我刚刚搜索了“hash table dos”并找到了一个信息页面:The moment when you realize every server in the world is vulnerable

    【讨论】:

      猜你喜欢
      • 2012-12-10
      • 1970-01-01
      • 2021-12-31
      • 2020-12-13
      • 1970-01-01
      • 1970-01-01
      • 2015-07-27
      • 2013-04-09
      • 2015-07-29
      相关资源
      最近更新 更多