示例说明
Argon2id 是当前密码哈希的首选:内存与时间成本双参数让 GPU 与 ASIC 攻击都昂贵。passlib 的价值在于参数自描述——成本参数编码在哈希字符串里,verify_and_update 验证的同时检测是否需要重哈希:提升参数或换算法后,存量用户在下次登录时透明迁移到新参数,无需批量重置。
技术要点
- 成本参数随密文内联存储
- verify_and_update 返回升级信号
- 内存成本六万四千 KiB 抗 GPU
代码解读
主上下文配置 ID 变体与三组成本参数;verify_password 验证失败返回 None 不区分原因防侧信道,需要升级时当场重哈希返回新密文供替换存储。模拟的低参数旧哈希验证后被识别为待升级并产出新参数密文。
使用建议
参数提升要压测登录吞吐再灰度。内存成本受容器内存限制约束。verify_and_update 的升级结果必须落库否则每次登录都重算。
代码示例
from passlib.context import CryptContext
context = CryptContext(
schemes=['argon2'],
argon2__type='ID',
argon2__time_cost=3,
argon2__memory_cost=65536,
argon2__parallelism=4,
deprecated='auto',
)
def hash_password(plain: str) -> str:
return context.hash(plain)
def verify_password(plain: str, stored: str) -> str | None:
ok, needs_rehash = context.verify_and_update(plain, stored)
if not ok:
return None
if needs_rehash:
# 参数升级或算法换代:下次登录时透明重哈希
return context.hash(plain)
return stored
record = hash_password('correct horse battery staple')
print('format:', record.split('$')[1])
print('wrong password:', verify_password('wrong', record) is None)
print('right password keeps hash:', verify_password('correct horse battery staple', record) == record)
# 模拟旧参数哈希:verify_and_update 报告需要升级
weaker = CryptContext(schemes=['argon2'], argon2__time_cost=1, argon2__memory_cost=8192)
legacy_record = weaker.hash('correct horse battery staple')
upgraded = verify_password('correct horse battery staple', legacy_record)
print('legacy upgraded:', upgraded != legacy_record)