web-dev-qa-db-fra.com

fonction de hachage dans Python 3.3 renvoie des résultats différents entre les sessions

J'ai implémenté un BloomFilter dans python 3.3, et obtenu des résultats différents à chaque session. L'exploration de ce comportement étrange m'a amené à la fonction de hachage interne () - il renvoie des valeurs de hachage différentes pour la même chaîne chaque session.

Exemple:

>>> hash("235")
-310569535015251310

----- ouverture d'une nouvelle console python -----

>>> hash("235")
-1900164331622581997

Pourquoi cela arrive-t-il? Pourquoi est-ce utile?

51
redlus

Python utilise une graine de hachage aléatoire pour empêcher les attaquants de tarer votre application en vous envoyant des clés conçues pour entrer en collision. Voir divulgation de vulnérabilité d'origine . En compensant le hachage avec une graine aléatoire (définie une fois au démarrage), les attaquants ne peuvent plus prédire quelles clés entreront en collision.

Vous pouvez définir une valeur fixe ou désactiver la fonctionnalité en définissant la variable d'environnement PYTHONHASHSEED ; la valeur par défaut est random mais vous pouvez la définir sur une valeur entière positive fixe, 0 désactivant complètement la fonctionnalité.

Les versions Python 2.7 et 3.2 ont la fonctionnalité désactivée par défaut (utilisez le commutateur -R Ou définissez PYTHONHASHSEED=random Pour l'activer); il est activé par défaut dans Python 3.3 et plus.

Si vous dépendiez de l'ordre des clés dans un dictionnaire ou un ensemble Python, alors ne le faites pas. Python utilise une table de hachage pour implémenter ces types et leurs ordre dépend de l'historique d'insertion et de suppression ainsi que la graine de hachage aléatoire.

Voir aussi la documentation de la méthode spéciale object.__hash__() :

Remarque : Par défaut, les valeurs __hash__() des objets str, bytes et datetime sont "salées" avec une valeur aléatoire imprévisible. Bien qu'ils restent constants au sein d'un processus individuel Python, ils ne sont pas prévisibles entre les invocations répétées de Python.
Ceci est destiné à fournir une protection contre un déni de service causé par des entrées soigneusement choisies qui exploitent les performances les plus défavorables d'une insertion de dict, la complexité O (n ^ 2). Voir http://www.ocert.org/advisories/ocert-2011-003.html pour plus de détails.
La modification des valeurs de hachage affecte l'ordre d'itération des dictés, des ensembles et d'autres mappages. Python n'a jamais fourni de garanties sur cet ordre (et il varie généralement entre les versions 32 bits et 64 bits).
Voir aussi PYTHONHASHSEED.

Si vous avez besoin d'une implémentation de hachage stable, vous voudrez probablement regarder le module hashlib ; cela implémente des fonctions de hachage cryptographiques. Le le projet pybloom utilise cette approche .

Étant donné que l'offset se compose d'un préfixe et d'un suffixe (valeur de départ et valeur XORed finale, respectivement), vous ne pouvez pas simplement stocker l'offset, malheureusement. Du côté positif, cela signifie que les attaquants ne peuvent pas non plus déterminer facilement le décalage avec des attaques de synchronisation.

77
Martijn Pieters

La randomisation par hachage est activée par défaut dans Python . Il s'agit d'une fonction de sécurité:

La randomisation par hachage est destinée à fournir une protection contre un déni de service provoqué par des entrées soigneusement choisies qui exploitent les performances les plus défavorables d'une construction dict

Dans les versions précédentes de 2.6.8, vous pouviez l'activer sur la ligne de commande avec -R ou l'option d'environnement PYTHONHASHSEED .

Vous pouvez le désactiver en définissant PYTHONHASHSEED sur zéro.

5
Peter Wood