从Python 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字节盐和PBKDF2的100000迭代与Python文档中建议的最小数目相匹配。进一步增加迭代次数将使散列的计算速度变慢,因此更加安全。
os.urandom
始终使用加密安全的随机源
hmac.compare_digest
在中使用的is_correct_password
,基本上只是==
字符串的运算符,但没有短路能力,这使其不受定时攻击的影响。那可能实际上并没有提供任何额外的安全性价值,但是也没有什么坏处,所以我继续使用它。
有关如何进行良好的密码哈希处理的理论以及适用于对密码进行哈希处理的其他功能的列表,请参见https://security.stackexchange.com/q/211/29805。
t_sha.digest() + salt
。您可以在对盐腌的哈希密码进行解码后,再将盐分出去,因为您知道解码后的哈希密码正好是32个字节。