You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 2.0中生成1000次迭代SHA256哈希的问题求助

问题排查及修复方案

核心问题点

  • 新旧实现逻辑不匹配:旧实现每次调用都会生成随机128位盐,且每轮迭代都会将上一轮哈希结果与盐拼接后再做哈希;新实现完全没有加盐逻辑,输入源存在本质差异,生成结果必然不一致。同时旧实现因为每次盐随机,哪怕输入相同密码、相同迭代次数,每次调用返回的结果也会不同,且未将盐与最终哈希共同存储,后续根本无法完成哈希验证,本身存在逻辑缺陷。
  • 迭代计算规则不一致:旧实现每轮迭代的输入是「上一轮哈希字节的Base64编码 + 盐字节的Base64编码」转UTF8字节;新实现每轮迭代的输入只有上一轮哈希结果的Base64编码转UTF8字节,输入内容不同,哈希结果自然不符。
  • 加密实例的冗余创建:新实现每次调用CreateSHA256Hash都会新建SHA256实例,虽然不影响算法结果,但存在不必要的性能开销。

修复方案

方案1:兼容旧逻辑的调整实现

如果需要和旧逻辑生成的哈希对齐,需要保留加盐逻辑,同时将盐与最终哈希共同存储方便后续验证,示例代码如下:

using System.Security.Cryptography;
using System.Text;

// 输出格式:$"盐Base64|最终哈希Base64",方便后续拆分验证
public static string CreateSHA256HashWithIteration(string password, int iterations = 1000)
{
    try
    {
        // 生成128位随机盐
        byte[] saltArr = new byte[128 / 8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetNonZeroBytes(saltArr);
        }

        using (var sha256 = SHA256.Create())
        {
            byte[] buffer = Encoding.UTF8.GetBytes(password);
            for (int i = 0; i < iterations; i++)
            {
                // 按旧逻辑拼接上一轮哈希Base64 + 盐Base64
                string combineStr = Convert.ToBase64String(buffer) + Convert.ToBase64String(saltArr);
                buffer = Encoding.UTF8.GetBytes(combineStr);
                buffer = sha256.ComputeHash(buffer);
            }
            // 返回盐+哈希,方便后续验证
            return $"{Convert.ToBase64String(saltArr)}|{Convert.ToBase64String(buffer)}";
        }
    }
    catch
    {
        return "Exception";
    }
}

// 验证哈希的配套方法
public static bool VerifySHA256Hash(string password, string storedHash, int iterations = 1000)
{
    try
    {
        var parts = storedHash.Split('|');
        if (parts.Length != 2) return false;
        byte[] saltArr = Convert.FromBase64String(parts[0]);
        byte[] storedHashBytes = Convert.FromBase64String(parts[1]);

        using (var sha256 = SHA256.Create())
        {
            byte[] buffer = Encoding.UTF8.GetBytes(password);
            for (int i = 0; i < iterations; i++)
            {
                string combineStr = Convert.ToBase64String(buffer) + Convert.ToBase64String(saltArr);
                buffer = Encoding.UTF8.GetBytes(combineStr);
                buffer = sha256.ComputeHash(buffer);
            }
            return buffer.SequenceEqual(storedHashBytes);
        }
    }
    catch
    {
        return false;
    }
}

方案2:更安全的官方推荐实现

手动实现迭代哈希容易出现逻辑漏洞,ASP.NET Core 2.0 推荐直接使用内置的Rfc2898DeriveBytes类实现PBKDF2标准的密码哈希,示例如下:

using System.Security.Cryptography;
using System.Text;

public static string HashPassword(string password, int iterations = 1000)
{
    byte[] salt = new byte[16];
    using (var rng = RandomNumberGenerator.Create())
    {
        rng.GetBytes(salt);
    }
    var hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, HashAlgorithmName.SHA256, 32);
    return $"{Convert.ToBase64String(salt)}|{iterations}|{Convert.ToBase64String(hash)}";
}

public static bool VerifyPassword(string password, string storedHash)
{
    var parts = storedHash.Split('|');
    if (parts.Length != 3) return false;
    byte[] salt = Convert.FromBase64String(parts[0]);
    int iterations = int.Parse(parts[1]);
    byte[] storedHashBytes = Convert.FromBase64String(parts[2]);
    var computedHash = Rfc2898DeriveBytes.Pbkdf2(password, salt, iterations, HashAlgorithmName.SHA256, 32);
    return computedHash.SequenceEqual(storedHashBytes);
}

内容的提问来源于stack exchange,提问作者Jitendra Pancholi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 15:06:07