编程乐土

编程乐土

逝将去女,适彼乐土。乐土乐土,爰得我所。记录计算机科学相关的知识。

Token明文与哈希存储验证区别

2026 年 11 月 07 日

两种做法的本质区别:数据库(连同备份、日志、快照)泄露后,攻击者拿到的是"能直接用的钥匙",还是"一堆没用的指纹"。

  • 明文存放:签发 token → 原文入库 → 验证时 WHERE token = 传入值
  • 哈希存放:签发 token → hash(token) 入库 → 验证时 WHERE token_hash = hash(传入值)

后者里,明文 token 只在"发给用户那一次"存在,之后连系统自己都不知道原文是什么。

安全差异

泄露的爆炸半径

  • 明文泄露 攻击者立刻能冒充任意用户,直到 token 过期
  • 哈希泄露 拿到一堆无法反推的指纹

内部人风险

有 DB 读权限的运维、DBA、被攻陷的只读副本,都能直接盗用明文 token;哈希则挡住了这条路径。

意外泄露

明文 token 容易随着慢查询日志、错误上报、备份文件、内存 dump 流出去;哈希后这类事故的危害大幅降低。

和加密的比较

  • token 哈希用 SHA-256 就够了,不需要 bcrypt/Argon2。 token 是高熵随机串(32 字节 CSPRNG),不存在"弱口令被字典/彩虹表打穿"的问题;慢哈希是为低熵密码设计的。只有当 token 很短或含可预测内容时才考虑慢哈希。
  • 哈希后依然能精确查找、照常建索引,不需要遍历全表。 token 哈希是确定性的(不像密码 hash 带随机 salt),同样输入永远同样输出,查询性能和明文几乎没差别。
  • 不要用"加密"代替哈希。 加密要额外管密钥;哈希是单向的,更契合"服务端本来也不需要原文"这个事实。

什么时候用哈希

  • 建议一律哈希:refresh token、长效 session、API key、密码重置 / 邮箱验证 token、OAuth 授权码——凡是"长期有效 + 高权限 + 落库"的。
  • 可以不哈希:几分钟就过期且带尝试次数限制的一次性验证码;以及服务端根本不存储的无状态 JWT(压根不入库,谈不上存明文)。

使用哈希存储token的代价

  • 无法直接去数据库查看/调试某个 token,排查线上问题略麻烦
  • 无法"重发同一个旧 token",只能重新签发
  • 存量数据迁移时要重新哈希一遍
  • 多一次哈希计算的 CPU 开销,可忽略