Skip to content

5.6 密码加密服务 ​

概述

密码加密由 utility/crypto 实现:bcrypt(password+salt) 双重加盐。外部 salt 存库、bcrypt 内部再加盐,双层防御彩虹表与拖库攻击。旧 md5 数据被 IsBcrypt 识别并拒绝登录(强制重置升级)。

加密与校验(utility/crypto) ​

函数职责
GenerateSalt生成 8 字节随机盐,base64url 编码截 10 位
HashPasswordbcrypt(password+salt),Cost=DefaultCost
VerifyPasswordbcryptHash 与 password+salt 比对
IsBcrypt识别是否 bcrypt 格式($2a$/$2b$ 前缀)

双重加盐设计 ​

text
存储形态:user 表的 password 列(bcrypt 哈希)+ salt 列(外部盐)

加密:HashPassword(明文, salt) = bcrypt(明文 + salt)
校验:VerifyPassword(存储哈希, 明文, salt)
        → 内部计算 bcrypt(明文 + salt) 与存储哈希比对

为什么双重加盐:
  * bcrypt 自带 cost 迭代 + 内部盐 → 防彩虹表、抗暴力
  * 外部 salt 存库 → 即使哈希算法被攻破,攻击者还需拿到 salt 列
  * 同密码不同用户哈希不同 → 拖库后无法横向碰撞

密码路径全景 ​

路径行为
用户新增(user.Add)GenerateSalt + HashPassword(事务外预计算),salt 与 password 同插入
用户修改密码(index.UpdatePassword)旧密码校验(1012 原密码错误)→ 新密码 bcrypt → 更新
重置密码(user.ResetPwd)未传新密码时重置为系统默认密码;管理员操作,logType=reset
用户导入(user.Import)未提供密码的行使用默认密码统一 bcrypt
登录(auth.Login)VerifyPassword 比对;旧 md5 数据被 IsBcrypt 拒绝

事务纪律(重要) ​

bcrypt 必须在事务外预计算

bcrypt 是 CPU 密集操作(DefaultCost 约 6-10ms/次)。事务内做 bcrypt 会拉长行锁持有时间。项目纪律:

text
❌ WithTrans(ctx, func(ctx) error {
       hash := HashPassword(...)   // CPU 密集在事务内
       dao.User.Ctx(ctx).Data(...).Insert()
   })

✅ hash := HashPassword(...)       // 事务外预计算
   WithTrans(ctx, func(ctx) error {
       dao.User.Ctx(ctx).Data(...).Insert()   // 事务内只做 DB 操作
   })

租户开户(tenant.Account)与用户新增(user.Add)均遵循此纪律;事务内同时禁止 HTTP/文件 IO。

旧数据兼容(md5 → bcrypt 升级) ​

text
IsBcrypt(存储值):
  true  → 正常 bcrypt 比对
  false → 旧 md5 数据:登录直接拒绝,提示重置密码

拒绝而非自动迁移的原因:md5 无盐(或弱盐)数据无法安全地"验旧写新",强制重置是更安全的升级路径。

安全清单 ​

text
* bcrypt DefaultCost(框架默认,够用;更高安全场景可显式提升 cost)
* salt 为独立列,永不返回接口(GetUser/Detail 均不含 password/salt)
* 操作日志脱敏:param 中 password/oldPassword/newPassword/salt → ***
* 修改密码走旧密码校验(本人)或 ResetPwd(管理员,留审计)
* 无独立复杂度策略——业务层未强制,可按需在密码路径追加规则

小蚂蚁云团队 · 提供技术支持