SHA256.Create() 必须用 using 包裹释放资源,否则哈希状态残留导致结果不可靠;字符串哈希前须统一用 Encoding.UTF8.GetBytes(),避免跨平台不一致;ComputeHash() 结果需用 Convert.ToHexString().ToLowerInvariant() 转为十六进制字符串。

SHA256.Create() 返回的实例必须用 using 包裹
不释放会导致内部哈希状态残留,多次调用可能出错,尤其在高并发或循环中。.NET 的 SHA256 实现是可变状态对象,不是纯函数。
- 错误写法:
var hash = SHA256.Create(); byte[] result = hash.ComputeHash(...);—— 没有Dispose(),资源泄漏且后续调用结果不可靠 - 正确写法:必须
using (var hash = SHA256.Create()) { ... } - 注意:
SHA256.Create("System.Security.Cryptography.SHA256Managed")这种字符串重载已废弃,.NET 5+ 会抛PlatformNotSupportedException
字符串转字节数组前必须明确编码,不能直接用 Encoding.Default
中文、emoji 或特殊符号在不同系统上 Encoding.Default 含义不同(Windows 是 GBK,Linux/macOS 是 UTF-8),同一串字符串加密结果不一致,无法跨平台校验。
- 一律用
Encoding.UTF8.GetBytes(input),这是事实标准 - 不要用
input.ToCharArray()或Convert.FromBase64String()直接喂给哈希——那不是原始字符串的字节表示 - 如果输入本来就是 Base64 编码的密文,先
Convert.FromBase64String(input)再哈希;但这是极少数场景,99% 的需求是哈希明文字符串本身
别把 ComputeHash() 结果直接当字符串用
返回的是 byte[],直接 .ToString() 得到的是类型名,不是哈希值;常见错误是看到输出 System.Byte[] 就以为“没算出来”。
- 要转成可读格式:用
BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant()得到 64 位小写十六进制字符串 - 或更高效:用
Convert.ToHexString(hashBytes).ToLowerInvariant()(.NET 5+) - 别用
Encoding.UTF8.GetString(hashBytes)—— 二进制哈希字节几乎不可能构成合法 UTF-8 序列,会得到乱码或异常
Web 场景下注意时钟偏移与常量时间比较
如果你拿 SHA256 做签名验证(比如 API 请求签名),光算哈希不够,还涉及安全比对逻辑。
- 服务端收到签名后,需用相同密钥和参数重新计算,并用
CryptographicOperations.FixedTimeEquals()比较结果,防止时序攻击 - 别用
==或SequenceEqual()—— 它们在遇到第一个不同字节就返回,攻击者能据此推断签名长度甚至部分字节 - 如果涉及时间戳(如
timestamp=1717023456),确保服务端和客户端系统时间偏差在容忍范围内,否则签名永远不匹配
using 释放——这两个点一错,本地跑得通,部署到 Linux 容器或另一台 Windows 机器就哈希对不上。









