Подтвердить что ты не робот

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

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

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

PYTHONHASHSEED

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

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

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

4b9b3361

Ответ 1

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

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


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

#! /bin/bash
export PYTHONHASHSEED=0

# call your python program here

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

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

$ PYTHONHASHSEED=0 python YOURSCRIPT.py

Ответ 2

Помимо порядка словаря, рандомизация хэшей также может нарушить существующий код, который напрямую использует 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)