Python 3.3'teki hash işlevi, oturumlar arasında farklı sonuçlar döndürür


106

Python 3.3'te bir BloomFilter uyguladım ve her oturumda farklı sonuçlar aldım. Bu garip davranışı incelemek beni dahili hash () işlevine götürdü - her oturumda aynı dize için farklı hash değerleri döndürür.

Misal:

>>> hash("235")
-310569535015251310

----- yeni bir python konsolu açmak -----

>>> hash("235")
-1900164331622581997

Bu neden oluyor? Bu neden yararlıdır?

Yanıtlar:


141

Python, size çarpışmak üzere tasarlanmış anahtarlar göndererek saldırganların uygulamanızı batırmasını önlemek için rastgele bir karma tohum kullanır. Orijinal güvenlik açığı açıklamasına bakın . Karmayı rastgele bir tohumla dengeleyerek (başlangıçta bir kez ayarlanır) saldırganlar artık hangi anahtarların çarpışacağını tahmin edemez.

PYTHONHASHSEEDOrtam değişkenini ayarlayarak sabit bir çekirdek belirleyebilir veya özelliği devre dışı bırakabilirsiniz ; varsayılan randomdeğerdir, 0ancak özelliği tamamen devre dışı bırakarak sabit bir pozitif tam sayı değerine ayarlayabilirsiniz .

Python 2.7 ve 3.2 sürümlerinde bu özellik varsayılan olarak devre dışı bırakılır ( etkinleştirmek için -Ranahtarı veya seti PYTHONHASHSEED=randomkullanın); Python 3.3 ve sonraki sürümlerde varsayılan olarak etkindir.

Bir Python setindeki anahtarların sırasına güveniyorsanız, o zaman güvenmeyin. Python, bu türleri uygulamak için bir karma tablo kullanır ve bunların sırası , ekleme ve silme geçmişinin yanı sıra rastgele karma tohumuna da bağlıdır. Python 3.5 ve daha eski sürümlerde bunun sözlükler için de geçerli olduğunu unutmayın.

Ayrıca object.__hash__()özel yöntem belgelerine bakın :

Not : Varsayılan olarak, __hash__()str, bayt ve datetime nesnelerinin değerleri tahmin edilemeyen rastgele bir değerle "tuzlanmıştır". Tek bir Python sürecinde sabit kalmalarına rağmen, Python'un tekrarlanan çağrıları arasında tahmin edilemezler.

Bu, bir dikt eklemenin en kötü durum performansını, O (n ^ 2) karmaşıklığını kullanan, dikkatle seçilmiş girdilerin neden olduğu bir hizmet reddine karşı koruma sağlamayı amaçlamaktadır. Ayrıntılar için http://www.ocert.org/advisories/ocert-2011-003.html adresine bakın.

Karma değerlerin değiştirilmesi, diktlerin, kümelerin ve diğer eşlemelerin yineleme sırasını etkiler. Python, bu sıralama hakkında hiçbir zaman garanti vermemiştir (ve genellikle 32 bit ve 64 bit yapılar arasında değişir).

Ayrıca bakınız PYTHONHASHSEED.

Kararlı bir hash uygulamasına ihtiyacınız varsa, muhtemelen hashlibmodüle bakmak istersiniz ; bu, kriptografik hash işlevlerini uygular. Pybloom projesi bu yaklaşımı kullanır .

Göreli konum bir ön ek ve bir son ek içerdiğinden (sırasıyla başlangıç ​​değeri ve son XORed değeri) maalesef ofseti saklayamazsınız. Artı tarafta, bu, saldırganların zamanlama saldırılarıyla ofseti kolayca belirleyemeyeceği anlamına gelir.


13
Bunun sadece __hash __ () değil, hash () dokümanlarında görünmesini bekliyorum. Harika bir cevap için +1. ps Hashlib, hash fonksiyonlarının kriptografik olmayan kullanımları için bir aşırılık değil mi?
redlus

1
pybloom, hashlib işlevlerini kullanır. Ancak daha hızlı bir şey istiyorsanız, pyhash'i kontrol edebilirsiniz .
Håken Lid

3
Dokümantasyon disableonu 0 olarak ayarlarken neden çağırıyor ? Bir şeyi kaçırmadığım sürece, onu herhangi bir eski sabit tohum numarasına ayarlamak için etkili bir fark görmüyorum. Demek istediğim, kullandığım zaman PYTHONHASHSEED=12345, oturumlar arasında bile eşit dizeler için aynı hash elde ediyorum - kullandığımda da aynı şey oluyor PYTHONHASHSEED=0- eşit dizeler için hash, oturumlar boyunca aynı olacak (12345'ten farklı olsa da, ama bu çok açık, bu nasıl tohumlar iş).
blubberdiblub

@blubberdiblub: 0hiç çekirdek yok ve nesnelere yönelik karmalar, herhangi bir karma tohum desteği olmadan eski bir Python sürümünde oluşturulanlara eşittir.
Martijn Pieters

1
@MartijnPieters Etkilenen karmaların "hiç tohum içermemesi" ne anlama geliyor? Aralarında hash değerlerinin farklı olduğu ve PYTHONHASHSEED = 0'ın eski sürümlere eşit olduğu iki ayrı oturum dizisi oluşturması dışında, mesela 12345 tohumuna sahip olmanın anlamsal veya niteliksel farkı nedir? Beni belirli bir kaynak koduna bağlayabilir misin? Sanırım demek istediğim, eğer böyle bir fark yoksa, ona 0 ve daha eski Python sürümlerinin tohumu diyebilirim, sadece 0 tohumunu destekler. Şu anki haliyle dokümantasyon benim için oldukça kafa karıştırıcı.
blubberdiblub

10

Karma rasgeleleştirme, Python 3'te varsayılan olarak açıktır . Bu bir güvenlik özelliğidir:

Karma randomizasyon, bir dikt yapısının en kötü durum performansından yararlanan dikkatle seçilmiş girdilerin neden olduğu bir hizmet reddine karşı koruma sağlamayı amaçlamaktadır.

2.6.8'den önceki sürümlerde, komut satırında -R veya PYTHONHASHSEED ortam seçeneğiyle açabiliyordunuz .

PYTHONHASHSEEDSıfıra ayarlayarak kapatabilirsiniz .


-11

hash () bir Python yerleşik fonksiyonudur ve onu string veya num için değil, nesne için bir hash değeri hesaplamak için kullanır .

Ayrıntıları bu sayfada görebilirsiniz: https://docs.python.org/3.3/library/functions.html#hash .

ve hash () değerleri nesnenin __hash__ yönteminden gelir. Doktor şunları söylüyor:

Varsayılan olarak, str, bayt ve datetime nesnelerinin hash () değerleri tahmin edilemeyen rastgele bir değerle "tuzlanır". Tek bir Python sürecinde sabit kalmalarına rağmen, Python'un tekrarlanan çağrıları arasında tahmin edilemezler.

Bu nedenle, farklı konsollarda aynı dizge için farklı bir hash değeriniz vardır.

Uyguladığınız şey iyi bir yol değil.

Bir string hash değerini hesaplamak istediğinizde, sadece hashlib kullanın

hash (), bir karıştırma değil, bir nesne karma değeri elde etmeyi amaçlar.


6
hash()dize veya sayısal değerler için mükemmel şekilde geçerlidir. Sen bu karıştırıyorsun __hash__kullanılan özel bir yöntem, ilehash() karma değerinin özel bir uygulama sağlamak.
Martijn Pieters
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.