2014-12-17 36 views
23

arasındaki farklı sonuçları döndürür Python 3.3'te bir BloomFilter uyguladım ve her oturumda farklı sonuçlar aldım. Bu garip davranışı sonlandırmak beni dahili hash() işlevine getirdi - her oturumda aynı dize için farklı karma değerler döndürüyor.Python 3.3 hash işlevi, oturumlar

Örnek:

>>> hash("235") 
-310569535015251310 

-----

yeni piton konsolu -----

>>> hash("235") 
-1900164331622581997 

neden oluyor açılması? Bu neden yararlı?

+2

Bu bir güvenlik özelliğidir. –

+0

Tagged [etiket: hash-çarpışma], [tag: güvenlik], [tag: python-3.3] – smci

cevap

38

Python, saldırganların çarpışmak üzere tasarlanmış anahtarlar göndererek uygulamanızı katledilmesini önlemek için rasgele bir hash tohumu kullanır. original vulnerability disclosure'a bakın. Saldırıyı rastgele bir tohumla (başlangıçta bir kez ayarla) dengelemek, saldırganların hangi tuşların çarpışacağını artık tahmin edemez.

Sabit bir tohum ekleyebilir veya özelliği PYTHONHASHSEED environment variable; varsayılan random'dur, ancak özelliği tamamen devre dışı bırakan 0 ile sabit bir pozitif tamsayı değerine ayarlayabilirsiniz.

Python sürümleri 2.7 ve 3.2, varsayılan olarak özelliği devre dışı bırakmıştır (etkinleştirmek için -R anahtarını kullanın veya PYTHONHASHSEED=random'u ayarlayın); Python 3.3 ve üzeri varsayılan olarak etkinleştirilmiştir.

Python sözlüğünde tuşların sırasına güveniyorsanız veya ayarladıysanız, yapmayın. Python, bu türleri ve bunların sırasını depends on the insertion and deletion history ve rastgele hash tohumu uygulamak için bir karma tablo kullanır.

Not:

da object.__hash__() special method documentation bkz Varsayılan olarak, str byte ve tarih saat nesneleri __hash__() değerleri tahmin edilemeyen bir rastgele değere sahip “tuzlu” dir. Her bir Python işleminde sabit kalsalar da, Python'un tekrarlanan çağrıları arasında tahmin edilemezler.
Bu, bir dict ekleme, O (n^2) karmaşıklığının en kötü durum performansından yararlanan özenle seçilmiş girdilerin neden olduğu bir hizmet reddine karşı koruma sağlamak amacıyla tasarlanmıştır. Detaylar için http://www.ocert.org/advisories/ocert-2011-003.html'a bakın.
Karma değerlerinin değiştirilmesi, dicts, set ve diğer eşleştirmelerin yineleme sırasını etkiler. Python bu sipariş hakkında hiçbir zaman garanti vermedi (ve genellikle 32-bit ve 64-bit sürümleri arasında değişiyor).
Ayrıca bkz. PYTHONHASHSEED.

Sabit bir karma uygulamasına ihtiyacınız varsa, muhtemelen hashlib module; Bu kriptografik karma fonksiyonları uygular. pybloom project uses this approach.

Ofset bir önek ve sonek (sırasıyla başlangıç ​​değeri ve son XOR değeri) oluşur, maalesef yalnızca ofseti depolayamazsınız. Artı tarafta, bu, saldırganların zamanlama saldırıları ile ofsetleri kolayca belirleyemediği anlamına gelir.

+0

Bunun hash() belgesinde görünmesini beklerdim, sadece __hash __(). Mükemmel bir cevap için +1. p.s. hashlib'in hash işlevlerinin kriptografik kullanımları için bir overkill değil mi? – redlus

+0

pybloom, hashlib işlevlerini kullanır. Ancak daha hızlı bir şey istiyorsanız, [pyhash] 'a bakabilirsiniz (https://github.com/flier/pyfasthash). –

+0

Neden belge 0 olarak ayarlandığında 'devre dışı' diyor? Bir şeyi kaçırmadığım sürece, herhangi bir eski sabit tohum numarasına ayarlanmasında etkili farkı görmüyorum. Demek istediğim, "PYTHONHASHSEED = 12345" kullandığımda, oturumlar arasında bile eşit dizeler için aynı kareyi aldığımda - PYTHONHASHSEED = 0 'kullandığımda aynı şey olur - eşit dizgiler için karma, (farklı da olsa) 12345'e kadar, ama bu açıktır, tohumlar böyle işliyor). – blubberdiblub

3

Karma rasgele ayrıştırma turned on by default in Python 3'dur.Bu bir güvenlik özelliğidir:

Hash randomizasyon karşı koruma sağlamak üzere tasarlanmıştır reddi-of-service dict yapımında önceki olarak

en kötü durum performansını istismar özenle seçilmiş girdiler neden 2.6.8 sürümleri, -R veya PYTHONHASHSEED ortam seçeneği ile komut satırında açabilirsiniz.

Sıfırlamak için PYTHONHASHSEED ayarını kapatabilirsiniz.

+0

Bu özellik yalnızca özelliği nasıl devre dışı bırakacağını açıklıyor, ilk başta neden orada olduğunu açıklamıyor. –

+1

@MartijnPieters Cevabımı yaptığınız gibi genişletmek için zaman ayırmadım. –

-2

karma() bir Python yerleşik işlev olup dize veya num için, nesne için bir karma değerini hesaplamak için kullanır.

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

ve hash() değerleri, nesnenin __hash__ yönteminden gelir. doc Aşağıdakiler diyor: Varsayılan olarak

, str, bayt ve datetime nesneleri karma() değerleri tahmin edilemez bir rasgele değer ile “tuzlu” vardır. Her bir Python işleminde sabit kalsalar da, Python'un tekrarlanan çağrıları arasında tahmin edilemezler.

Bu nedenle, farklı konsoldaki aynı dizge için farklı karma değeriniz olmalıdır.

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

Eğer sadece bir nesne karma değer değil, bir stirng almak amacı() hashlib

karma kullanmak, bir dize karma değerini hesaplamak istediğinizde.

+3

'hash()', dize veya sayısal değerler için mükemmel şekilde geçerlidir. Bunu hash değerinin özel bir uygulamasını sağlamak için hash() '** tarafından kullanılan' __hash__' özel yöntemiyle karıştırıyorsunuz. –