A partir de Python 3.4, el hashlib
módulo de la biblioteca estándar contiene funciones de derivación de claves que están "diseñadas para el cifrado seguro de contraseñas" .
Entonces use uno de esos, como hashlib.pbkdf2_hmac
, con una sal generada usando 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')
Tenga en cuenta que:
- El uso de una sal de 16 bytes y 100000 iteraciones de PBKDF2 coinciden con los números mínimos recomendados en los documentos de Python. Aumentar aún más el número de iteraciones hará que sus hashes sean más lentos de calcular y, por lo tanto, más seguros.
os.urandom
siempre utiliza una fuente de aleatoriedad criptográficamente segura
hmac.compare_digest
, utilizado en is_correct_password
, es básicamente el ==
operador de cadenas pero sin la capacidad de cortocircuito, lo que lo hace inmune a los ataques de sincronización. Eso probablemente no proporciona ningún valor de seguridad adicional , pero tampoco hace daño, así que seguí adelante y lo usé.
Para obtener una teoría sobre lo que hace un buen hash de contraseña y una lista de otras funciones apropiadas para usar el hash de contraseñas, consulte https://security.stackexchange.com/q/211/29805 .
t_sha.digest() + salt
. Puede dividir la sal nuevamente más tarde cuando haya decodificado la contraseña hash con sal, ya que sabe que la contraseña hash decodificada tiene exactamente 32 bytes.