bigywater.tech
Flask · 130

密码哈希与密码升级

密码该怎么存?默认的哈希够不够强?库里还有旧的弱哈希怎么办?这篇量出每种方法的真实耗时,并实现一遍「登录时顺便升级」的流程。

66 ms
Werkzeug 默认 scrypt 哈希一次的耗时(单核)
约 93085 倍
scrypt 默认相对一次 sha256 的耗时
登录时升级
用户登录成功、手里有明文密码时把旧哈希重新哈希写回

哈希的格式

实测 · 本机执行输出
  默认哈希: scrypt:32768:8:1$1BqMQRrogW6XwUBP$627fa23b94221e17cbf4a374b1… (长度 162)
  同一个密码再来一次: scrypt:32768:8:1$DaH1695lpnGSOVxb$9d6a5c809885b3eccdc7d682b9… | 两次相同吗: False
  结构:方法$盐$摘要 → scrypt:32768:8:1 | 盐 16 个字符 | 摘要 128 个十六进制字符
  check_password_hash 正确/错误: True False

上一篇:Rate Limiting;下一篇:登录失败锁定。

各方法的耗时

实测 · 本机执行输出
  pbkdf2:sha256:1000(旧的、太弱)                 0.131 ms
  pbkdf2:sha256:600000                     65.161 ms
  scrypt(Werkzeug 默认 32768:8:1)            66.000 ms
  scrypt:131072:8:1                       266.391 ms
  argon2id(argon2-cffi 默认)                 30.137 ms
  sha256 一次(错误示范,不要用)                       0.001 ms
  差距:scrypt 默认比单次 sha256 慢 93085 倍

密码升级

实测 · 本机执行输出
  升级前: {'ann': 'pbkdf2:sha256:1000', 'bob': 'scrypt:32768:8:1'}
  ann 用错误的密码登录: fail | 哈希仍是 pbkdf2:sha256:1000
  ann 正确登录: ok(并已升级哈希)
  ann 再登录一次: ok | bob 登录: ok
  升级后: {'ann': 'scrypt:32768:8:1', 'bob': 'scrypt:32768:8:1'}
  (没有登录过的用户仍是旧哈希——升级只发生在用户登录、明文密码在手的时候)

参数在哈希里

实测 · 本机执行输出
  旧参数哈希头: scrypt:16384:8:1 | 新参数哈希头: scrypt:131072:8:1
  两者都能用同一个 check_password_hash 验证: True True

超长与空密码

实测 · 本机执行输出
  10 万个字符的密码哈希耗时 67.4 ms,哈希长度 162
  空字符串密码也能哈希并验证: True
  (这次测量里耗时没有随密码长度明显增加,和默认的 65 ms 差不多;是否仍要在应用层限制密码长度,这里没有验证)

argon2

实测 · 本机执行输出
   $argon2id$v=19$m=65536,t=3,p=4$ww695w9iuw7iKH0hmnKluQ$/fE07J…
  验证: True | check_needs_rehash(默认参数): False
  用更弱参数生成的哈希,按默认参数 check_needs_rehash → True (argon2-cffi 自带「是否需要升级」的判断)

argon2-cffi 是我额外装进环境的,Flask 与 Werkzeug 本身不带它。

分步演示

密码哈希与升级
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。Werkzeug 3.1.9、argon2-cffi 25.1.0
    • 没有验证:bcrypt 与 passlib 的行为、pepper(应用层的额外密钥)、哈希在 GPU 或专用硬件上的破解成本(这里只量了本机单核的耗时)、数据库里已有哈希的批量迁移与回滚、密码强度策略
    京ICP备2026067502号-1京公网安备11010502063487号