Python Hash的一致性問題
問題描述
某個專案在爬蟲進行爬蟲時有做重複性資料的去重時,發現無法正常過濾比對,在觀察後,發現相同文字內容的在進行Hash,所得的結果不一致,而導致比對內容發生問題
問題重現
引發這個錯誤的環境
- 有三台主機執行相同的程式碼,每次取得的內容會進行Hash處理後,比對資料庫內保存的文章Hash值進行比對
- 每台主機最多開5個執行緒,三台共15個執行緒再跑
- Python 版本:3.5.10
問題重現的範例
將上述的程式碼用2個Python解釋器去執行,可以得到下面結果
(第一個視窗執行,Hash=-4036149443421515860)
(第二個視窗執行,Hash=-2834029426068990657)
後續做幾個簡單的小測試
- 相同執行緒下,相同輸入的Hash值相同
- 同一個執行緒下,多個子線程的Hash值相同
- 每次重新執行程式,Hash值不同
問題原因
Python在計算字符串的hash值時,會加入隨機的前綴和後綴(加鹽),以提升計算的複雜度和安全性。
若要關閉前綴和後綴得加鹽,可以將PYTHONHASHSEED環境變數設定成0
下面是關閉的方式
import os
import sys
hashseed = os.getenv('PYTHONHASHSEED')
os.environ['PYTHONHASHSEED'] = '0'
os.execv(sys.executable, [sys.executable] + sys.argv)
自我思考
雖然以目前的專案情境,關閉這個選項似乎不影響安全性,因為畢竟只是單純爬蟲拿頁面資料,但是如果其他需要有更高安全性的情境的話,關閉這個應該會引起HashDoS的問題
為了避免影響後續專案環境,還是
不要關閉比較好,可能須使用命令列的方式或者使用MD5處理,畢竟Python會這樣設計主要就是為了安全性
這邊紀錄一下使用MD5處理的範例
不同版本的PYTHONHASHSEED參數環境變量
- Python 2.x
- 預設情況下,PYTHONHASHSEED 環境變量是關閉的。
- 每次啟動 Python 時,hash 的前後綴都會設置為 0。
- 可以透過設置 PYTHONHASHSEED 環境變量來啟用隨機性。
- Python 3.x
- 如果不顯式設置 PYTHONHASHSEED 環境變量,則會預設隨機生成前後綴值。
- 每次啟動解釋器時,hash 算法的結果都會有所不同。
