今天我的目標是進行一個簡單的實作,學習如何用加鹽(Salted Hash)的技術來保護密碼,有效防禦破解攻擊。
當我們只對密碼進行哈希處理,像是用 SHA-256 或 MD5,如果兩個使用者使用相同的密碼,最終哈希出來的結果會一模一樣。攻擊者只需要預計算好常見密碼的哈希值,就可以輕易破解一大堆使用相同密碼的帳號,這也就是彩虹表攻擊。
加鹽(Salt)的概念就是給每個密碼加上一個隨機的鹽值,即使兩個人用的是相同的密碼,因為各自的鹽值不同,最終生成的哈希值也會不同,即使有彩虹表也會變得沒用。
import hashlib
import os
def generate_salt():# 生成鹽值
return os.urandom(16) # 生成16字節的隨機鹽值
def hash_password(password, salt):# 生成鹽加密後的哈希
# 將鹽值與密碼結合,再進行 SHA-256 哈希
return hashlib.sha256(salt + password.encode()).hexdigest()
def verify_password(stored_hash, password, salt):# 驗證密碼
# 重新生成輸入的密碼哈希,並與存儲的哈希值比對
return stored_hash == hash_password(password, salt)
salt = generate_salt() # 生成隨機鹽值
password = "admin" # 你的密碼
hashed_password = hash_password(password, salt) # 生成哈希
print("存儲的哈希:", hashed_password)
print("鹽值:", salt)
is_valid = verify_password(hashed_password, "admin", salt)
print("密碼驗證結果:", "正確" if is_valid else "錯誤")
生成鹽值
generate_salt()
這個函數用到 Python 的 os.urandom()
,這個函數會生成一個 16 字節長的隨機字串,這就是鹽值。每次呼叫這個函數,生成的鹽值都會不一樣。
生成哈希
hash_password()
函數將使用者輸入的密碼和剛剛生成的鹽值結合起來,然後用 hashlib
套件來計算它們的 SHA-256 哈希。
驗證密碼
當使用者下一次登入時,會用 verify_password()
函數來驗證密碼。這個函數的做法是取出之前存儲的鹽值,然後用同樣的哈希函數將輸入的密碼進行處理,再把計算出的哈希值與存儲的哈希值做對比。如果相同就代表密碼正確。
存儲的哈希: 5d41402abc4b2a76b9719d911017c592
鹽值: b'\xb1\xd8\x11\xe7\xff\xec\xd3...
密碼驗證結果: 正確
執行完後會生成一個帶鹽的哈希,並用它來驗證密碼,鹽值讓攻擊者無法僅靠事先計算好的彩虹表來破解密碼,即便多個使用者的密碼相同,最終的哈希值也不同。這樣攻擊者就需要針對每個密碼和鹽值重新進行破解,增加攻擊的難度。