ในฐานะที่เป็นของงูใหญ่ 3.4 ที่hashlib
โมดูลในห้องสมุดมาตรฐานมีรากศัพท์ที่สำคัญฟังก์ชั่นที่มีการ"ออกแบบมาสำหรับการแปลงแป้นพิมพ์รหัสผ่านที่ปลอดภัย"
ดังนั้นใช้หนึ่งในสิ่งเหล่านี้เช่นhashlib.pbkdf2_hmac
กับเกลือที่สร้างขึ้นโดยใช้os.urandom
:
from typing import Tuple
import os
import hashlib
import hmac
def hash_new_password(password: str) -> Tuple[bytes, bytes]:
"""
Hash the provided password with a randomly-generated salt and return the
salt and hash to store in the database.
"""
salt = os.urandom(16)
pw_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
return salt, pw_hash
def is_correct_password(salt: bytes, pw_hash: bytes, password: str) -> bool:
"""
Given a previously-stored salt and hash, and a password provided by a user
trying to log in, check whether the password is correct.
"""
return hmac.compare_digest(
pw_hash,
hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
)
salt, pw_hash = hash_new_password('correct horse battery staple')
assert is_correct_password(salt, pw_hash, 'correct horse battery staple')
assert not is_correct_password(salt, pw_hash, 'Tr0ub4dor&3')
assert not is_correct_password(salt, pw_hash, 'rosebud')
โปรดทราบว่า:
- การใช้เกลือ 16 ไบต์และการทำซ้ำ 100000 ของ PBKDF2 จะตรงกับตัวเลขขั้นต่ำที่แนะนำในเอกสาร Python การเพิ่มจำนวนการทำซ้ำเพิ่มเติมจะทำให้แฮชของคุณคำนวณได้ช้าลงและปลอดภัยมากขึ้น
os.urandom
ใช้แหล่งที่มาของการสุ่มที่ปลอดภัยโดยเข้ารหัสเสมอ
hmac.compare_digest
โดยพื้นฐานแล้วใช้is_correct_password
เป็นเพียงตัว==
ดำเนินการสำหรับสตริง แต่ไม่มีความสามารถในการลัดวงจรซึ่งทำให้ไม่มีภูมิคุ้มกันต่อการโจมตีตามเวลา นั่นอาจไม่ได้ให้ค่าความปลอดภัยเพิ่มเติมแต่ก็ไม่เจ็บเช่นกันดังนั้นฉันจึงใช้มันต่อไป
สำหรับทฤษฎีในสิ่งที่ทำให้กัญชารหัสผ่านที่ดีและรายชื่อของฟังก์ชั่นอื่น ๆ ที่เหมาะสมสำหรับรหัสผ่านคร่ำเครียดกับการดูhttps://security.stackexchange.com/q/211/29805
t_sha.digest() + salt
ทั้งสองร่วมกัน คุณสามารถแยกเกลือออกอีกครั้งในภายหลังเมื่อคุณได้ถอดรหัสรหัสผ่านแฮชแบบเค็มเนื่องจากคุณทราบว่ารหัสผ่านแฮชที่ถอดรหัสนั้นมีขนาด 32 ไบต์