Ab Python 3.4 hashlib
enthält das Modul in der Standardbibliothek Funktionen zur Schlüsselableitung , die "für sicheres Passwort-Hashing ausgelegt sind" .
Verwenden Sie also eines davon, z. B. hashlib.pbkdf2_hmac
mit einem Salz, das erzeugt wird aus 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')
Beachten Sie, dass:
- Die Verwendung eines 16-Byte-Salt und 100000 Iterationen von PBKDF2 entsprechen den in den Python-Dokumenten empfohlenen Mindestzahlen. Wenn Sie die Anzahl der Iterationen weiter erhöhen, werden Ihre Hashes langsamer berechnet und sind daher sicherer.
os.urandom
verwendet immer eine kryptografisch sichere Zufallsquelle
hmac.compare_digest
, verwendet in is_correct_password
, ist im Grunde nur der ==
Operator für Strings, aber ohne die Fähigkeit zum Kurzschließen, was es immun gegen Timing-Angriffe macht. Das bietet wahrscheinlich keinen zusätzlichen Sicherheitswert , aber es tut auch nicht weh, also habe ich es verwendet.
Eine Theorie darüber, was einen guten Passwort-Hash ausmacht, und eine Liste anderer Funktionen, die zum Hashing von Passwörtern geeignet sind, finden Sie unter https://security.stackexchange.com/q/211/29805 .
t_sha.digest() + salt
. Sie können das Salt später wieder aufteilen, wenn Sie das Salted-Hash-Passwort dekodiert haben, da Sie wissen, dass das decodierte Hash-Passwort genau 32 Byte beträgt.