Python 3.3中的哈希函数在会话之间返回不同的结果

red*_*lus 68 python security hash hash-collision python-3.3

我已经在python 3.3中实现了BloomFilter,并且每次会话都得到了不同的结果.深入研究这种奇怪的行为让我进入了内部的hash()函数 - 它为每个会话返回相同字符串的不同哈希值.

例:

>>> hash("235")
-310569535015251310
Run Code Online (Sandbox Code Playgroud)

-----打开一个新的python控制台-----

>>> hash("235")
-1900164331622581997
Run Code Online (Sandbox Code Playgroud)

为什么会这样?为什么这有用?

Mar*_*ers 102

Python使用随机散列种子来防止攻击者通过向您发送旨在发生冲突的密钥来对您的应用程序进行tar.请参阅原始漏洞披露.通过使用随机种子(在启动时设置一次)来抵消哈希,攻击者无法再预测哪些密钥会发生冲突.

您可以通过设置PYTHONHASHSEED环境变量来设置固定种子或禁用该功能; 默认值是,random但您可以将其设置为固定的正整数值,并0完全禁用该功能.

Python版本2.7和3.2默认禁用该功能(使用-R开关或设置PYTHONHASHSEED=random启用它); 它在Python 3.3及更高版本中默认启用.

如果您依赖于Python字典或集合中的键顺序,那么请不要这样做.Python使用哈希表来实现这些类型,它们的顺序取决于插入和删除历史以及随机哈希种子.

另请参阅object.__hash__()特殊方法文档:

注意:默认情况下,__hash__()str,bytes和datetime对象的值是"salted"的,具有不可预测的随机值.虽然它们在单个Python进程中保持不变,但是在重复调用Python之间它们是不可预测的.
这旨在提供针对由精心选择的输入引起的拒绝服务的保护,该输入利用dict插入的最坏情况性能,O(n ^ 2)复杂度.有关详细信息,请参见http://www.ocert.org/advisories/ocert-2011-003.html.
更改哈希值会影响dicts,集和其他映射的迭代顺序.Python从未对此排序做出保证(通常在32位和64位版本之间有所不同).
另见PYTHONHASHSEED.

如果你需要一个稳定的哈希实现,你可能想看一下这个hashlib模块 ; 这实现了加密哈希函数.该pybloom项目采用这种做法.

由于偏移量由前缀和后缀(分别为起始值和最终XORed值)组成,因此不幸的是,您不能仅存储偏移量.从好的方面来说,这确实意味着攻击者也无法轻易确定定时攻击的偏移量.

  • 为什么文档在将其设置为 0 时称其为“禁用”?我没有看到将其设置为任何旧的稳定种子号的有效差异,除非我遗漏了一些东西。我的意思是,当我使用 `PYTHONHASHSEED=12345` 时,即使在多个会话之间,我也会得到相同的字符串哈希值 - 当我使用 `PYTHONHASHSEED=0` 时也会发生同样的情况 - 会话间相等字符串的哈希值将相同(尽管不同到 12345,但这很明显,这就是种子的工作方式)。 (3认同)
  • 我希望这会显示在hash()文档中,而不仅会出现在__hash __()中。+1是个不错的答案。ps hashlib对于散列函数的非加密使用不是过度的杀伤力吗? (2认同)
  • pybloom 使用 hashlib 函数。但是如果你想要更快的东西,你可以查看 [pyhash](https://github.com/flier/pyfasthash)。 (2认同)

Ben*_*ida 17

hash()当我尝试比较会话之间保存在数据库中的记录时,这种行为让我绊倒了。

PYTHONHASHSEED解决方案太复杂了,因为我需要我的程序可靠地工作,独立于环境变量设置。

因此,我创建了简单的 has 函数,该函数对字符串进行哈希处理(很容易将任何内容转换为字符串)并生成一个 32 位正整数作为哈希值。它不是加密安全的哈希值,但足以进行快速比较。

def myHash(text:str):
  hash=0
  for ch in text:
    hash = ( hash*281  ^ ord(ch)*997) & 0xFFFFFFFF
  return hash
Run Code Online (Sandbox Code Playgroud)

乘法中的数字只是任意选择的素数,以便混合位。

如果您希望哈希值是十六进制字符串,则可以将最后一行替换为:

return hex(hash)[2:].upper().zfill(8)
Run Code Online (Sandbox Code Playgroud)

  • 它一定要慢得多,因为它是纯 Python 代码,无法与标准库中基于 C 的代码竞争。根据您的用例对其进行测试,看看是否可用。 (2认同)

Pet*_*ood 7

默认情况下,Python 3中会启用哈希随机化.这是一个安全功能:

散列随机化旨在提供保护,防止因精心挑选的输入引起的拒绝服务,这些输入利用了dict构造的最坏情况性能

在2.6.8的先前版本中,您可以使用-R或PYTHONHASHSEED环境选项在命令行中打开它.

您可以通过设置PYTHONHASHSEED为零来关闭它.