← 中文资源

简体中文版本

Passlib Argon2 密码哈希

用 passlib 的 Argon2id 哈希密码:算法参数随密文存储,旧参数哈希在下次登录验证时透明升级,错误口令零信息返回。

阅读英文原文

示例说明

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)