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

时间:2014-12-17 09:48:18

标签: python security hash python-3.3 hash-collision

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

示例:

>>> hash("235")
-310569535015251310

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

>>> hash("235")
-1900164331622581997

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

3 个答案:

答案 0 :(得分:71)

Python使用随机散列种子来防止攻击者通过向您发送旨在发生冲突的密钥来对您的应用程序进行tar操作。请参阅original vulnerability disclosure。通过使用随机种子(在启动时设置一次)来抵消散列,攻击者无法再预测哪些密钥会发生冲突。

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

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

如果您依赖于Python字典或集合中的键顺序,那么请不要这样做。 Python使用哈希表来实现这些类型及其顺序depends on the insertion and deletion history以及随机哈希种子。

另见object.__hash__() special method documentation

  

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

如果您需要稳定的哈希实现,您可能希望查看hashlib module;这实现了加密哈希函数。 pybloom project uses this approach

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

答案 1 :(得分:5)

哈希随机化是turned on by default in Python 3。这是一项安全功能:

  

哈希随机化旨在提供针对由精心挑选的输入引起的拒绝服务的保护,这些输入利用了dict构造的最坏情况性能

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

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

答案 2 :(得分:-5)

hash()是一个Python 内置函数,用它来计算对象的哈希值,而不是字符串或数字

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

和hash()值来自对象的__hash__方法。 该文件说明如下:

  

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

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

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

如果要计算字符串哈希值,只需使用hashlib

hash()旨在获取对象哈希值,而不是搅拌。