不能直接用crypto/sha512做密码哈希,因其无盐值、无迭代、不抗GPU并行计算,易被彩虹表和暴力破解;应改用bcrypt或PBKDF2等带盐+迭代+可调成本的密钥派生函数。

crypto/sha512 本身不提供迭代(如 PBKDF2、scrypt 那种多轮哈希),直接调用它做密码存储等于裸奔——攻击者用 GPU 一秒钟就能跑几亿次,撞库毫无门槛。真要提高防撞库门槛,必须绕开 sha512.Sum512 这类单次哈希,改用带盐 + 迭代 + 可调成本的密钥派生函数。
为什么不能直接用 crypto/sha512 做密码哈希
SHA-512 是通用哈希,设计目标是快和确定性,不是抗暴力破解。它没有内置盐、没有迭代次数、不阻塞 GPU/ASIC 并行计算。用户密码 "123456" 经 sha512.Sum512 处理后,全球任意设备算出的结果都一样,彩虹表或预计算哈希集可直接命中。
该用哪个包:优先选 golang.org/x/crypto/bcrypt
bcrypt 是 Go 生态最成熟、被广泛审计的密码哈希方案,自带盐、自动迭代(cost 参数控制)、天然抗 GPU 加速。它不暴露原始哈希轮数,也不依赖你手动拼接盐和哈希值。
- 生成哈希:
hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)——DefaultCost当前是 10(即 2¹⁰ ≈ 1024 轮),生产环境建议设为 12–14 - 验证时直接比对原文:
err := bcrypt.CompareHashAndPassword(hashed, []byte(input)),无需自己拆盐、重算 - 哈希结果含 salt 和 cost,格式如
$2a$12$...,可安全存数据库,无需额外字段存 salt - 别用
bcrypt.New或自己调bcrypt.Cost算哈希——那是底层构造器,易误用导致无 salt 或固定 salt
如果必须用 SHA-512 做密钥派生,就走 crypto/x/crypto/pbkdf2
仅在合规要求明确指定“必须用 SHA-2 家族”(如某些金融接口)时才考虑。PBKDF2 不是银弹,但能补足迭代和盐:
- 盐必须随机且足够长:
salt := make([]byte, 32); rand.Read(salt)—— 硬编码 salt 或复用 salt 会让所有用户共享同一攻击面 - 迭代次数至少 100,000 轮:
pbkdf2.Key([]byte(password), salt, 100000, 64, sha512.New),低于 60,000 轮在现代 CPU 上耗时不足 10ms,起不到延缓作用 - 输出长度建议 64 字节(匹配 SHA-512 输出),太短会削弱熵
- 别把 salt 拼进密码再哈希(
sha512.Sum512(append(salt, pwd...)))——这不叫加盐,只是预处理,完全没用
容易被忽略的落地细节
真正卡住撞库的,往往不是算法选型,而是这些实操断点:
立即学习“go语言免费学习笔记(深入)”;
- 数据库字段长度不够:bcrypt 哈希约 60 字符,PBKDF2 base64 后约 86 字符,
VARCHAR(60)会截断,必须设为VARCHAR(128)或以上 - HTTP body 解析未限制长度:攻击者发超长密码(如 1MB)触发哈希计算 OOM,应提前用
http.MaxBytesReader限流 - 登录接口没做请求频控:即使哈希慢,不限制每 IP 每分钟尝试次数,照样被暴力扫
- 错误提示泄露信息:
"password wrong"和"user not found"应统一返回,避免用户名枚举
防撞库不是堆参数的事——cost 设到 30 不如 salt 每次都新生成来得实在。安全水位取决于最弱一环,而那一环,十有八九是你没写进代码的那行配置或没加上的那道限流。


















