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


96

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

例:

>>> hash("235")
-310569535015251310

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

>>> hash("235")
-1900164331622581997

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

Answers:


136

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

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

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

如果您依赖于Python集合中键的顺序,那么就不用了。Python使用哈希表来实现这些类型,它们的顺序取决于插入和删除的历史记录以及随机哈希种子。请注意,在Python 3.5及更低版本中,这也适用于字典。

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

注意:默认情况下,__hash__()str,bytes和datetime对象的值使用不可预测的随机值“加盐”。尽管它们在单个Python进程中保持不变,但在重复调用Python之间是不可预测的。

这旨在提供保护,防止由于精心选择的输入而导致的拒绝服务,这些输入利用了dict插入的最坏情况的性能O(n ^ 2)复杂性。有关详细信息,请参见http://www.ocert.org/advisories/ocert-2011-003.html

更改哈希值会影响字典,集合和其他映射的迭代顺序。Python从未保证过这种顺序(通常在32位和64位版本之间有所不同)。

另请参阅PYTHONHASHSEED

如果需要稳定的哈希实现,则可能需要查看hashlib模块;这实现了加密哈希函数。该pybloom项目采用这种做法

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


8
我希望这会显示在hash()文档中,而不仅会出现在__hash __()中。+1是个不错的答案。ps hashlib对于散列函数的非加密使用不是过度的杀伤力吗?
redlus 2014年

1
pybloom使用hashlib函数。但是,如果您想要更快的速度,可以查看pyhash
哈肯·利德

3
为什么将文档disable设置为0时会调用它?我看不到将其设置为任何旧的稳定种子编号的有效区别,除非我缺少某些内容。我的意思是,当我使用PYTHONHASHSEED=12345相同的字符串时,即使在整个会话期间也得到相同的哈希值-使用时也会发生相同的情况PYTHONHASHSEED=0-相等的字符串的哈希值在整个会话期间将相同(尽管与12345不同,但这很明显,这就是种子的方式)工作)。
blubberdiblub

@blubberdiblub:0根本没有种子,并且对象的哈希值等于在没有任何哈希种子支持的旧Python版本中生成的哈希值。
马丁·彼得斯

1
@MartijnPieters受影响的哈希表“根本没有种子”是什么意思?除了说它创建了两个不同的会话集(哈希值不同)而且PYTHONHASHSEED = 0等于较早版本之外,拥有种子(例如12345)有什么语义或质量上的区别?您可以将我链接到特定的源代码吗?我想我的意思是,如果没有这种差异,我会称其为0的种子,而旧版本的Python仅支持0的种子。目前的文档对我来说很混乱。
blubberdiblub

10

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

散列随机化旨在提供保护,防止由于精心选择的输入而导致的拒绝服务攻击,这些输入利用了dict构造的最坏情况性能

在2.6.8之前的版本中,可以使用-R或PYTHONHASHSEED环境选项在命令行中将其打开

您可以将其设置PYTHONHASHSEED为零以将其关闭。


-9

hash()是Python的内置函数,可用于为对象而不是字符串或num 计算哈希值。

您可以在以下页面中查看详细信息:https : //docs.python.org/3.3/library/functions.html#hash

hash()值来自对象的__hash__方法。该文档说以下内容:

默认情况下,str,bytes和datetime对象的hash()值会以不可预测的随机值“成盐”。尽管它们在单个Python进程中保持不变,但在重复调用Python之间是不可预测的。

这就是为什么您在不同的控制台中对同一字符串具有不同的哈希值的原因。

您实施的方法不是一个好方法。

当您要计算字符串哈希值时,只需使用hashlib

hash()的目的是获取对象的哈希值,而不是搅动。


6
hash()对字符串或数字值完全有效。您与此混淆__hash__自定义的方法,用于通过hash()提供的哈希值的自定义实现。
马丁·彼得斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.