必须用 bcrypt.generatefrompassword 生成哈希、bcrypt.comparehashandpassword 验证,禁用 md5/sha256 加盐;明文需转 []byte 且 ≤72 字节,cost 推荐 defaultcost=12,哈希存 string 类型 varchar(255),验证时顺序不可颠倒,失败统一返回泛化提示。

别用 MD5 或 SHA256 加盐存密码,哪怕你手动生成了 32 字节随机 salt —— 它在 2026 年已完全失效。真正该用的只有 bcrypt.GenerateFromPassword,它把 salt、cost、hash 全打包进一个字符串,验证时也只靠 bcrypt.CompareHashAndPassword。
为什么不能自己拼 salt + hash
常见错误是:用 crypto/rand 生成 salt,再用 sha256.Sum256 算 hash,最后存两个字段。这看似“加了盐”,实则埋雷:
-
time.Now().Unix()或用户名当 salt —— 可预测,攻击者能预生成爆破表 - 拼接顺序写成
password + salt而非salt + password—— 若 salt 含\x00,C风格字符串会提前截断 - 数据库里 salt 和 hash 分开存,没做长度校验 —— 验证时
strings.Split(dbHash, "$")可能 panic 或越界 - 没控制明文长度 ——
bcrypt内部只取前 72 字节,"123456" + 100 个 x和"123456"哈希结果一样
bcrypt.GenerateFromPassword 的参数陷阱
这个函数看着简单,但翻车点全在细节上:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 第一个参数必须是
[]byte,不是string;传string会编译报错或静默转码出错 - cost 别硬写
10或14,优先用bcrypt.DefaultCost(当前为 12),它平衡了安全与延迟(约 40–60ms/次) - 明文超过 72 字节会被静默截断 —— 必须在调用前校验长度,比如限制前端传入 8–64 字符
- 哈希结果是 ASCII 字符串(如
$2a$12$...),存数据库直接用string(hashed),别存[]byte二进制,否则读出来乱码
验证必须用 CompareHashAndPassword,不能手写比较
有人图省事写 bytes.Equal(storedHash, computedHash),这是严重漏洞:
- 触发
timing attack:攻击者通过比对响应耗时差异,逐字推断密码 - 参数顺序不能反:第一个是数据库里读出的完整哈希字符串转成的
[]byte,第二个才是用户输入的明文[]byte - 返回
nil表示匹配成功;其他错误(如bcrypt.ErrMismatch)都算失败,别只判err != nil就完事 - 哈希字符串开头必须是
$2a$或$2b$,若从旧系统迁移来的是$2y$,不升级库会直接 panic
最易被忽略的一点:哈希值本身已自包含 salt 和 cost,你不需要、也不应该额外建字段存 salt;验证失败时对外必须统一返回泛化提示(如 “用户名或密码错误”),绝不能暴露 “密码错误” 或 “账号不存在” 这类信息 —— 否则等于帮攻击者做撞库探测。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










