C#验证Django pbkdf2_sha256哈希密码失败的问题求助
Django pbkdf2_sha256 密码验证在C#中不匹配的问题解决
问题根源
你的代码核心问题在于Django使用URL安全的Base64编码存储盐和哈希,而当前解码逻辑未处理这种编码格式差异:
- Django会把标准Base64中的
+替换为-,/替换为_,并且省略末尾的填充字符= - 原解码方法仅补充了
=,但未还原-和_为标准Base64字符,导致盐的字节数组错误,最终计算出的哈希自然不匹配。
修复后的代码
修改解码逻辑以兼容URL安全Base64,同时采用密码验证的安全最佳实践(常量时间比较):
public static bool VerifyPassword(string enteredPassword, string storedPasswordHash) { var parts = storedPasswordHash.Split('$'); if (parts.Length != 4 || parts[0] != "pbkdf2_sha256") { Console.WriteLine("Invalid password format."); return false; } if (!int.TryParse(parts[1], out int iterations)) { Console.WriteLine("Invalid iterations count."); return false; } byte[] saltBytes = DecodeUrlSafeBase64(parts[2]); if (saltBytes == null) { return false; } byte[] storedHashBytes = DecodeUrlSafeBase64(parts[3]); if (storedHashBytes == null) { return false; } byte[] passwordBytes = Encoding.UTF8.GetBytes(enteredPassword); byte[] computedHashBytes; using (var pbkdf2 = new Rfc2898DeriveBytes(passwordBytes, saltBytes, iterations, HashAlgorithmName.SHA256)) { computedHashBytes = pbkdf2.GetBytes(storedHashBytes.Length); // 适配存储的哈希长度 } // 常量时间比较,防止时序攻击 return CryptographicOperations.FixedTimeEquals(computedHashBytes, storedHashBytes); } private static byte[] DecodeUrlSafeBase64(string input) { // 还原URL安全Base64的特殊字符 string base64 = input.Replace('-', '+').Replace('_', '/'); // 补充缺失的填充字符 switch (base64.Length % 4) { case 2: base64 += "=="; break; case 3: base64 += "="; break; } try { return Convert.FromBase64String(base64); } catch (FormatException) { Console.WriteLine("Error decoding Base64 string."); return null; } }
关键修改说明
- URL安全Base64解码:新增
DecodeUrlSafeBase64方法,先将-和_替换回标准Base64的+和/,再处理填充,完全兼容Django的编码规则。 - 动态哈希长度:不再固定生成32字节哈希,而是根据存储的哈希长度动态生成,适配不同的Django配置。
- 安全比较方式:使用
CryptographicOperations.FixedTimeEquals替代直接数组相等判断,避免攻击者通过时序差异猜测密码,提升验证安全性。
内容的提问来源于stack exchange,提问作者username01
相关产品推荐
相关产品推荐

