不能用crypto/md5或crypto/sha1做密码哈希或签名,因为它们已被证实存在实际可利用的碰撞漏洞,攻击者能在几秒内构造出两个不同输入但哈希值完全相同的payload;md5输出仅16字节、sha-1碰撞工具(如shattered.io)已开源多年,二者均不再满足抗碰撞性要求,仅限非安全场景兼容性使用。

为什么不能用 crypto/md5 或 crypto/sha1 做密码哈希或签名
因为它们已被证实存在实际可利用的碰撞漏洞,攻击者能在几秒内构造出两个不同输入但哈希值完全相同的 payload。比如 md5.Sum([]byte("password")) 生成的哈希,可能被彩虹表或预计算攻击快速反查;sha1.New() 在 TLS 证书和 Git 提交中早已被主流系统弃用。
真实错误现象包括:用户密码被批量破解、API 签名被伪造、区块链交易哈希冲突导致双花——这些都不是理论风险,而是已有公开 PoC 的生产事故。
- MD5 输出仅 16 字节,空间太小,暴力搜索成本极低
- SHA-1 的碰撞构造工具(如
shattered.io)已开源多年 - Go 标准库仍保留这两个包,仅用于兼容性场景(如校验老固件 checksum),不是鼓励使用
crypto/sha256 和 crypto/sha512 的选型依据
两者都属于 SHA-2 家族,目前无已知实用碰撞攻击,但适用场景有明确区分:
- 一般 Web 应用、JWT 签名、密码派生(
pbkdf2/hkdf)首选sha256.New():性能好、内存占用低、输出长度(32 字节)足够覆盖绝大多数安全需求 - 金融级密钥派生、长期存档数据完整性校验、需要更高抗量子迁移余量的场景,才考虑
sha512.New():输出 64 字节,但 CPU 消耗高约 40%,且在 ARM 设备上可能因寄存器宽度导致轻微减速 - 注意:
sha512在 32 位架构上可能比预期慢,不是单纯“更安全就更好”
在 crypto/hmac 和 crypto/pbkdf2 中指定哈希函数的写法
这两个包不接受字符串算法名,必须传入哈希构造函数(即返回 hash.Hash 的函数),写错会导致编译失败或运行时 panic。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
正确写法示例:
h := hmac.New(sha256.New, key) derivedKey := pbkdf2.Key([]byte(password), salt, 100000, 32, sha256.New)
常见错误:
- 误写成
hmac.New("sha256", key)—— 编译不通过,hmac.New第一个参数类型是func() hash.Hash - 误用
md5.New替代sha256.New—— 逻辑能跑通,但安全性归零 - 在
pbkdf2.Key中漏掉最后一个参数(哈希构造函数),会触发panic: nil hash
真正容易被忽略的点:哈希函数只是链条一环
即使用了 sha256,如果盐值(salt)是固定字符串、迭代次数设为 1、密钥直接硬编码在代码里,整个防护就形同虚设。比如 pbkdf2.Key(pwd, []byte("fixed_salt"), 1, 32, sha256.New) —— 盐值不随机、迭代太低,GPU 集群可在数秒内暴力穷举。
关键不在“用哪个哈希”,而在于:盐值是否来自 crypto/rand.Read、迭代次数是否 ≥100000、密钥是否隔离存储、HMAC 是否防范时序攻击(用 hmac.Equal 而非 == 比较)。这些细节不处理,换再强的哈希也没意义。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










