Вопрос:

Отключить рандомизацию хеша из программы Python

python python-3.x hash

8057 просмотра

2 ответа

36524 Репутация автора

Начиная с Python 3.3, алгоритм хеширования недетерминированно солен, чтобы избежать определенного вида атаки. Это хорошо для веб-серверов, но это неприятно при попытке отладки программы: каждый раз, когда я запускаю свой скрипт, содержимое dict повторяется в другом порядке.

В некоторых более ранних версиях python был -Rфлаг для включения рандомизации хэшей, но теперь, когда это поведение по умолчанию, этот флаг не был заменен его противоположностью. Рандомизацию можно отключить, установив переменную окружения PYTHONHASHSEED:

PYTHONHASHSEED

Если эта переменная не установлена ​​или установлена ​​в значение random, случайное значение используется для заполнения хэшей объектов str, bytes и datetime.
Если для PYTHONHASHSEED задано целочисленное значение, оно используется в качестве фиксированного начального числа для генерации хеша () типов, охватываемых рандомизацией хеша.

Уловка в том, что эта переменная должна быть установлена ​​до запуска процесса python. Я пытался установить его с помощью os.putenv()или внутри os.environ, но, похоже, они не влияют на метод хеширования. Это не слишком удивительно: я бы не ожидал, что python будет проверять окружение перед каждым поиском набора или словаря! Итак, вопрос остается:

Есть ли способ для программы Python отключить свою собственную рандомизацию хеша?

Автор: alexis Источник Размещён: 01.06.2015 11:42

Ответы (2)


16 плюса

34132 Репутация автора

Решение

Я подозреваю, что это невозможно, к сожалению. Глядя test_hash.pyна HashRandomizationTestsкласс и его потомки были добавлены в коммит , который ввел это поведение . Они проверяют поведение хеширования, изменяя среду и запуская новый процесс с PYTHONHASHSEEDявно установленным значением. Возможно, вы могли бы попытаться скопировать этот шаблон.

Я также только что заметил, что вы сказали: « Каждый раз, когда я запускаю свой сценарий, содержание dict повторяется в другом порядке». - Я полагаю, вы знаете collections.OrderedDict, верно? Это нормальный способ получить надежную итерацию хеша.


Если вы хотите установить значение в своей оболочке, вы можете просто обернуть ваш вызов Python в скрипт bash, например

#! /bin/bash
export PYTHONHASHSEED=0

# call your python program here

Это избавляет от необходимости манипулировать всей вашей средой, пока вы в порядке со скриптом-оберткой.

Или даже просто передать значение в командной строке:

$ PYTHONHASHSEED=0 python YOURSCRIPT.py
Автор: dimo414 Размещён: 02.06.2015 01:48

-1 плюса

440 Репутация автора

Помимо порядка словаря, рандомизация хэшей также может нарушить существующий код, который использует hash()напрямую. Обходной путь, который решил проблему для меня в этом случае, должен был заменить

hash(mystring)

с участием

int(hashlib.sha512(mystring).hexdigest(), 16)

Для Python 3 потребуется преобразование типа `mystring.encode ('utf-8') для стандартных строк. (Я работал с байтовыми строками.)

Обратите внимание, что диапазон чисел и наличие отрицательных чисел различны. Последний код дает гораздо больший диапазон чисел, и коллизии хэшей крайне маловероятны.

Чтобы воспроизвести тот же 64-битный диапазон hash(), который можно уменьшить, можно уменьшить количество шестнадцатеричных цифр до 16 (4 бита на цифру) и сдвинуть результат так, чтобы он начинался с наименьшего отрицательного 64-битного числа:

int(hashlib.sha256(mystring).hexdigest()[:16], 16)-2**63

В качестве альтернативы можно взять 8 байтов и использовать int.from_bytes:

int.from_bytes(hashlib.sha256(mystring).digest()[:8], byteorder='big', signed=True)

Автор: Joachim Wagner Размещён: 28.09.2019 11:59
Вопросы из категории :
32x32