Iris 不内置密码哈希,需用 bcrypt.GenerateFromPassword() 手动处理盐值、成本因子和错误;禁用 sha256 或 bcrypt.Sum() 因其无盐无迭代;验证时须确保哈希值字节级完整未被截断或转义。

Iris 框架本身不内置密码哈希逻辑,它依赖 Go 标准库或第三方 bcrypt 实现(如 golang.org/x/crypto/bcrypt)完成密码加密。直接调用 bcrypt.GenerateFromPassword() 即可,无需 Iris 特殊封装 —— 但必须手动控制盐值、工作因子和错误处理,否则极易踩坑。
为什么不能直接用 bcrypt.Sum() 或 sha256 替代?
因为 bcrypt.Sum() 是标准哈希接口,不带盐、无工作因子、不可配置延时,等同于裸 MD5;而 sha256 是通用哈希函数,相同密码永远输出相同值,完全无法防御彩虹表。Bcrypt 的安全性正来自其强制加盐 + 自适应迭代的组合设计。
常见错误现象:
- 用
sha256.Sum256([]byte(pwd)).Sum(nil)存储密码 → 数据库泄露后秒破 - 误以为
bcrypt包里有Encrypt()或Hash()这类“快捷函数” → 实际只有GenerateFromPassword()和CompareHashAndPassword() - 忽略返回错误,把
err != nil当作“密码太长”忽略 → 实际可能是内存分配失败或非法 UTF-8
bcrypt.GenerateFromPassword() 的参数陷阱
该函数签名是:func GenerateFromPassword(password []byte, cost int) ([]byte, error)。关键点不在“怎么调”,而在“为什么这么传”:
-
password必须是[]byte,不是string—— 虽然 Go 允许隐式转换,但若原始字符串含 BOM 或代理对(如某些 emoji),直接转[]byte可能截断或错位;建议显式用utf8.Valid()校验 -
cost推荐设为12~14:低于10在现代 CPU 上耗时不足 50ms,易被暴力扫;高于16可能导致登录接口超时(尤其高并发时) - 不要复用同一盐值:
GenerateFromPassword内部已调用gensalt(),你传进去的cost仅控制迭代强度,盐值始终随机生成并嵌入返回的哈希字符串中
示例(安全写法):
hashed, err := bcrypt.GenerateFromPassword([]byte(userInput), 12)
if err != nil {
// 注意:err 可能是 bcrypt.ErrInvalidCost、bcrypt.ErrPasswordTooLong 等
log.Printf("bcrypt hash failed: %v", err)
return err
}
// hashed 形如 $2b$12$N9qo8uLOickgx2ZMRZMyQeAgtpGL6ebsJp.mXdf8Yp7dPpqPvm7SS
// 直接存入数据库,无需额外解析或拼接
Iris 中验证密码时最容易漏掉的一步
调用 bcrypt.CompareHashAndPassword() 前,必须确保从数据库读出的哈希值是完整原始字节(包括 $2b$ 开头),且未被 trim、url.QueryUnescape、JSON unmarshal 截断或转义。Iris 默认的 JSON 解析会静默丢弃末尾空格或误处理 $ 符号。
典型问题场景:
- 用
json.Unmarshal读用户结构体时,哈希字段定义为string但数据库字段类型是TEXT→ 若字段末尾有不可见字符(如换行),Go 的string会保留,但某些 ORM(如sqlx)可能自动 trim - 前端调试时把哈希值粘贴进 Postman,手动删了开头的
$→ 验证必然失败,报crypto/bcrypt: hashedPassword is not the hash of the given password - 哈希值被当成 URL 参数传递(如重置链接),没做
url.PathEscape→$和/被服务端解析丢失
验证代码务必这样写:
// 从 DB 读出的 rawHash 是 []byte 类型,未经任何字符串处理
err := bcrypt.CompareHashAndPassword(rawHash, []byte(inputPassword))
if err != nil {
// 注意:err == nil 才表示验证通过;err == bcrypt.ErrMismatchedHashAndPassword 表示密码错
return false
}
return true
真正麻烦的从来不是“怎么调 bcrypt 函数”,而是确保哈希值从生成、传输、存储到比对的每个环节都保持字节级一致 —— 少一个 $,多一个空格,或者一次无意识的 strings.TrimSpace(),都会让整个防护形同虚设。


















