Go 中只有 SHA256 哈希而非加密,不可逆;小字符串用 sha256.Sum256,大文件或流式数据用 sha256.New() + Write + Sum(nil);密码存储必须用 bcrypt 等专用算法,禁用裸 SHA256。

Go 里没有“SHA256 加密”这回事,只有 SHA256 哈希 —— 它不可逆、不加密,只是生成固定长度摘要。直接用 sha256.Sum256 或 sha256.New() + Write 就行,别被“加密”二字带偏。
sha256.Sum256():一行搞定小字符串哈希
这是最简方式,适合已知内容、无需流式处理的场景(比如密码摘要、配置校验)。它直接返回 [32]byte,不是切片,不能追加数据。
-
sha256.Sum256([]byte("hello"))返回的是值类型,sum[:]才转成[]byte供后续编码(如base64或hex) - 别写成
sha256.Sum256([]byte("hello")).Sum(nil)——Sum256本身不带Sum方法,编译报错 - 如果传空字符串
"",结果恒为cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce(32 字节十六进制),可作基准验证
sha256.New() + Write():处理大文件或分块数据的正确姿势
当你需要读取文件、接收 HTTP body、拼接多段数据时,必须用这个组合。核心是:先 Write,再 Sum(nil),顺序不能反。
-
h := sha256.New()创建状态对象,内部维护中间哈希值 - 多次调用
h.Write()是合法且高效的,比如h.Write([]byte("foo")); h.Write([]byte("bar"))等价于h.Write([]byte("foobar")) -
h.Sum(nil)才真正计算最终结果;若误写成h.Sum([]byte("prefix")),会把哈希值追加到 prefix 后面,导致长度变长、结果错误 - 对大文件务必用
io.Copy(h, file),而不是file.Read()后全量Write—— 否则可能 OOM
Base64 编码 SHA256 结果时的常见陷阱
很多协议(如 LDAP 密码格式)要求 Base64 编码原始哈希字节,而非十六进制字符串。这里最容易出错:
立即学习“go语言免费学习笔记(深入)”;
- 错误写法:
base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%x", hash)))—— 先转 hex 再 base64,结果是 hex 字符串的编码,不是原始 32 字节的编码 - 正确写法:
base64.StdEncoding.EncodeToString(hash[:])(hash是sha256.Sum256返回值)或base64.StdEncoding.EncodeToString(h.Sum(nil)) -
base64.StdEncoding输出含+//,若用于 URL 或文件名,应改用base64.URLEncoding避免特殊字符
密码存储别只用 SHA256
SHA256 是快速哈希,天生不适合存密码 —— 没有加盐、无法调节耗时,暴力破解成本极低。
- 即使加了 salt,也建议用
golang.org/x/crypto/bcrypt或scrypt,它们内置 salt 和可调工作因子 - 若协议强制要求 SHA256+salt 格式(如某些旧系统),务必确保 salt 是随机生成、足够长(至少 16 字节),且与哈希值一起持久化存储
-
sha256.Sum256(append([]byte(salt), []byte(password)...))这种拼接方式比简单连接更抗长度扩展攻击,但依然不如专用算法
真正麻烦的不是写几行哈希代码,而是搞清你要的是“校验和”还是“密码保护”——前者用 Sum256 直出,后者必须换 bcrypt。别在生产环境里用裸 SHA256 存密码,哪怕加了 salt。


















