Python 3.3의 해시 함수는 세션간에 다른 결과를 반환합니다.


99

Python 3.3에서 BloomFilter를 구현했으며 세션마다 다른 결과를 얻었습니다. 이 이상한 동작을 드릴 다운하면 내부 hash () 함수가 나타납니다. 세션마다 동일한 문자열에 대해 다른 해시 값을 반환합니다.

예:

>>> hash("235")
-310569535015251310

----- 새 파이썬 콘솔 열기 -----

>>> hash("235")
-1900164331622581997

왜 이런 일이 발생합니까? 이것이 왜 유용합니까?

답변:


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 프로젝트는이 방법을 사용합니다 .

오프셋은 접두사와 접미사 (각각 시작 값과 최종 XOR 값)로 구성되어 있으므로 불행히도 오프셋을 저장할 수 없습니다. 플러스 측면에서 이것은 공격자가 타이밍 공격으로 오프셋을 쉽게 결정할 수 없음을 의미합니다.


9
__hash __ ()뿐만 아니라 hash () 문서에도 이것이 나타날 것으로 기대합니다. 좋은 답변을 원하시면 +1하세요. 추신 hashlib는 해시 함수의 비 암호화 사용에 과잉 사용되지 않습니까?
redlus dec

1
pybloom은 hashlib 함수를 사용합니다. 그러나 더 빠른 것을 원한다면 pyhash를 확인할 수 있습니다 .
Håken Lid

3
disable0으로 설정할 때 문서에서 호출하는 이유는 무엇 입니까? 내가 뭔가를 놓치고 있지 않는 한, 오래된 안정된 시드 번호로 설정하는 것과 효과적인 차이를 보지 못했습니다. 내 말은 내가 사용할 때 PYTHONHASHSEED=12345세션 전체에서 동일한 문자열에 대해 동일한 해시를 얻습니다-사용할 때도 동일합니다 PYTHONHASHSEED=0-동일한 문자열에 대한 해시는 세션 전체에서 동일합니다 (12345와는 다르지만 분명합니다. 작업).
blubberdiblub

@blubberdiblub : 0시드가 전혀없고 객체에 대한 해시가 해시 시드 지원없이 이전 Python 버전에서 생성 된 것과 동일합니다.
Martijn Pieters

1
@MartijnPieters 영향을받은 해시가 "시드가 전혀 없음"이라는 것은 무엇을 의미합니까? 해시 값이 다르고 PYTHONHASHSEED = 0이 이전 버전과 동일한 두 개의 별개의 세션 세트를 생성한다는 사실을 제외하고 12345의 시드를 갖는 것과의 의미 또는 질적 차이는 무엇입니까? 저를 특정 소스 코드에 연결할 수 있습니까? 내 요점은 그러한 차이가 없다면 0의 시드라고 부르고 0의 시드 만 지원하는 이전 버전의 Python이라고 부를 것입니다. 현재 문서는 나에게 상당히 혼란 스럽습니다.
blubberdiblub

10

해시 무작위 화는 Python 3에서 기본적으로 켜져 있습니다. 이것은 보안 기능입니다.

해시 무작위 화는 dict 구성의 최악의 경우 성능을 악용하는 신중하게 선택한 입력으로 인한 서비스 거부에 대한 보호를 제공하기위한 것입니다.

2.6.8의 이전 버전에서는 -R 또는 PYTHONHASHSEED 환경 옵션 을 사용하여 명령 줄에서 수 있습니다.

PYTHONHASHSEED0 으로 설정 하여 끌 수 있습니다 .


-9

hash () 는 파이썬 내장 함수 이며 문자열이나 숫자가 아닌 object 의 해시 값을 계산하는 데 사용합니다 .

https://docs.python.org/3.3/library/functions.html#hash 페이지에서 세부 사항을 볼 수 있습니다 .

hash () 값은 객체의 __hash__ 메서드에서 가져옵니다. 문서는 다음과 같이 말합니다.

기본적 으로 str, bytes 및 datetime 개체 의 해시 () 값은 예측할 수없는 임의의 값으로 "절대"됩니다. 개별 Python 프로세스 내에서 일정하게 유지되지만 반복되는 Python 호출 간에는 예측할 수 없습니다.

이것이 다른 콘솔에서 동일한 문자열에 대해 다른 해시 값을 갖는 이유입니다.

구현하는 것은 좋은 방법이 아닙니다.

문자열 해시 값을 계산하려면 hashlib를 사용 하십시오.

hash ()는 흔들림이 아닌 객체 해시 값을 얻는 것을 목표로합니다.


6
hash()문자열 또는 숫자 값에 완벽하게 유효합니다. 당신은 이것을 혼동되어 __hash__사용되는 사용자 정의 방법 에 의해hash() 해시 값의 사용자 지정 구현을 제공 할 수 있습니다.
Martijn Pieters
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.