ฟังก์ชันแฮชใน Python 3.3 ส่งคืนผลลัพธ์ที่แตกต่างกันระหว่างเซสชัน


106

ฉันได้ติดตั้ง BloomFilter ใน python 3.3 แล้วและได้ผลลัพธ์ที่แตกต่างกันทุกเซสชัน การเจาะลึกพฤติกรรมแปลก ๆ นี้ทำให้ฉันไปที่ฟังก์ชัน hash () ภายในซึ่งจะส่งคืนค่าแฮชที่แตกต่างกันสำหรับสตริงเดียวกันทุกเซสชัน

ตัวอย่าง:

>>> hash("235")
-310569535015251310

----- การเปิดคอนโซลหลามใหม่ -----

>>> hash("235")
-1900164331622581997

เหตุใดจึงเกิดขึ้น เหตุใดจึงมีประโยชน์

คำตอบ:


140

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 ซ้ำ ๆ

สิ่งนี้มีวัตถุประสงค์เพื่อให้การป้องกันการปฏิเสธการให้บริการที่เกิดจากอินพุตที่เลือกอย่างระมัดระวังซึ่งใช้ประโยชน์จากประสิทธิภาพในกรณีที่เลวร้ายที่สุดของการแทรกคำสั่ง O (n ^ 2) ความซับซ้อน ดูรายละเอียดได้ที่http://www.ocert.org/advisories/ocert-2011-003.html

การเปลี่ยนค่าแฮชมีผลต่อลำดับการวนซ้ำของคำสั่งชุดและการแมปอื่น ๆ Python ไม่เคยรับประกันเกี่ยวกับการสั่งซื้อนี้ (และโดยทั่วไปจะแตกต่างกันระหว่างรุ่น 32 บิตและ 64 บิต)

PYTHONHASHSEEDดูเพิ่มเติม

หากคุณจำเป็นต้องมีการดำเนินงานที่มีเสถียรภาพกัญชาคุณอาจต้องการที่จะดูที่hashlibโมดูล ; สิ่งนี้ใช้ฟังก์ชันแฮชการเข้ารหัส โครงการ pybloom ใช้วิธีการนี้

เนื่องจากค่าชดเชยประกอบด้วยส่วนนำหน้าและส่วนต่อท้าย (ค่าเริ่มต้นและค่า XORed สุดท้ายตามลำดับ) คุณจึงไม่สามารถจัดเก็บค่าชดเชยได้อย่างน่าเสียดาย ในด้านบวกหมายความว่าผู้โจมตีไม่สามารถกำหนดค่าชดเชยได้อย่างง่ายดายด้วยการโจมตีตามเวลา


13
ฉันคาดหวังว่าสิ่งนี้จะปรากฏในเอกสาร hash () ไม่ใช่เฉพาะใน __hash __ () +1 สำหรับคำตอบที่ดี ps ไม่ใช่ hashlib overkill สำหรับการใช้ฟังก์ชัน hash แบบไม่เข้ารหัสหรือไม่?
redlus

1
pybloom ใช้ฟังก์ชัน hashlib แต่ถ้าคุณต้องการบางสิ่งบางอย่างได้เร็วขึ้นคุณสามารถตรวจสอบpyhash
ฝาHåken

3
เหตุใดเอกสารจึงเรียกมันdisableเมื่อตั้งค่าเป็น 0 ฉันไม่เห็นความแตกต่างที่มีประสิทธิภาพในการตั้งค่าเป็นหมายเลขเมล็ดพันธุ์ที่คงที่แบบเก่าเว้นแต่ฉันจะพลาดบางอย่าง สิ่งที่ฉันหมายถึงคือเมื่อฉันใช้PYTHONHASHSEED=12345ฉันได้รับแฮชเดียวกันสำหรับสตริงที่เท่ากันแม้ในเซสชัน - สิ่งเดียวกันนี้เกิดขึ้นเมื่อฉันใช้PYTHONHASHSEED=0- แฮชสำหรับสตริงที่เท่ากันจะเหมือนกันในทุกเซสชัน (แม้ว่าจะแตกต่างจาก 12345 แต่ก็ชัดเจนนั่นคือวิธีที่ seed งาน).
blubberdiblub

@blubberdiblub: 0ไม่มีเมล็ดพันธุ์เลยและแฮชสำหรับอ็อบเจ็กต์จะเท่ากับที่สร้างใน Python เวอร์ชันเก่าโดยไม่มีการสนับสนุนแฮชซีดใด ๆ
Martijn Pieters

1
@MartijnPieters แฮชที่ได้รับผลกระทบมี "ไม่มีเมล็ด" หมายความว่าอย่างไร อะไรคือความแตกต่างเชิงความหมายหรือเชิงคุณภาพในการมีเมล็ดพันธุ์เช่น 12345 นอกเหนือจากข้อเท็จจริงที่ว่ามันสร้างเซสชันที่แตกต่างกันสองชุดซึ่งค่าแฮชแตกต่างกันและนอกเหนือจาก PYTHONHASHSEED = 0 เท่ากับเวอร์ชันเก่า คุณช่วยเชื่อมฉันกับซอร์สโค้ดชิ้นใดชิ้นหนึ่งได้ไหม ฉันเดาว่าประเด็นของฉันคือถ้าไม่มีความแตกต่างฉันจะเรียกมันว่าเมล็ดพันธุ์ของ 0 และ Python เวอร์ชันเก่าที่รองรับเฉพาะ seed เป็น 0 เท่านั้นเอกสารประกอบตามที่แสดงในตอนนี้ค่อนข้างสับสนสำหรับฉัน
blubberdiblub

10

แฮสุ่มถูกเปิดโดยเริ่มต้นในหลาม 3 นี่คือคุณสมบัติด้านความปลอดภัย:

การสุ่มแฮชมีวัตถุประสงค์เพื่อให้การป้องกันการปฏิเสธการให้บริการที่เกิดจากปัจจัยการผลิตที่เลือกอย่างระมัดระวังซึ่งใช้ประโยชน์จากประสิทธิภาพในกรณีที่เลวร้ายที่สุดของการสร้างแบบเผด็จการ

ในเวอร์ชันก่อนหน้าจาก 2.6.8 คุณสามารถเปิดใช้งานได้ที่บรรทัดคำสั่งด้วย -R หรือตัวเลือกสภาพแวดล้อมPYTHONHASHSEED

คุณสามารถปิดได้โดยตั้งค่าPYTHONHASHSEEDเป็นศูนย์


-11

hash ()เป็นฟังก์ชันในตัว Python และใช้เพื่อคำนวณค่าแฮชสำหรับอ็อบเจ็กต์ไม่ใช่สำหรับสตริงหรือ num

ท่านสามารถดูรายละเอียดในหน้านี้: https://docs.python.org/3.3/library/functions.html#hash

และค่าแฮช () มาจากเมธอด __hash__ ของวัตถุ เอกสารระบุว่า:

โดยค่าเริ่มต้นค่าแฮช () ของอ็อบเจ็กต์ str, bytes และ datetime จะ "ถูกกำหนด" ด้วยค่าสุ่มที่ไม่สามารถคาดเดาได้ แม้ว่าจะคงที่ภายในกระบวนการ Python แต่ละรายการ แต่ก็ไม่สามารถคาดเดาได้ระหว่างการเรียกใช้ Python ซ้ำ ๆ

นั่นเป็นเหตุผลที่คุณมีค่าแฮชที่แตกต่างกันสำหรับสตริงเดียวกันในคอนโซลที่แตกต่างกัน

สิ่งที่คุณใช้ไม่ใช่วิธีที่ดี

เมื่อคุณต้องการคำนวณค่าแฮชสตริงให้ใช้แฮชลิบ

แฮช () มีจุดมุ่งหมายเพื่อให้ได้ค่าแฮชของวัตถุไม่ใช่การกวน


6
hash()ใช้ได้อย่างสมบูรณ์แบบสำหรับค่าสตริงหรือตัวเลข คุณมีความสับสนนี้ด้วย__hash__วิธีการที่กำหนดเองที่ใช้โดยhash()จะให้ดำเนินการเองของมูลค่ากัญชา
Martijn Pieters
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.