【问题标题】:Is this a good way to encrypt passwords with MD5?这是用 MD5 加密密码的好方法吗?
【发布时间】:2026-02-19 14:30:01
【问题描述】:

我以前从未加密过密码,这就是我在this article 的帮助下想到的。这篇文章没有加盐,所以我必须自己弄清楚:

        UTF8Encoding encoder = new UTF8Encoding();
        byte[] salt = new byte[8];
        new Random().NextBytes(salt);
        byte[] encodedPassword = encoder.GetBytes(txtPassword.Text);
        byte[] saltedPassword = new byte[8 + encodedPassword.Length];
        System.Buffer.BlockCopy(salt, 0, saltedPassword, 0, 8);
        System.Buffer.BlockCopy(encodedPassword, 0, saltedPassword, 8, encodedPassword.Length);
        byte[] encryptedPassword = new MD5CryptoServiceProvider().ComputeHash(saltedPassword);
        byte[] saltedEncryptedPassword = new byte[8 + encryptedPassword.Length];
        System.Buffer.BlockCopy(salt, 0, saltedEncryptedPassword, 0, 8);
        System.Buffer.BlockCopy(encryptedPassword, 0, saltedEncryptedPassword, 8, encryptedPassword.Length);

saltedEncryptedPassword 存储在数据库中。正如您可能注意到的那样,我在将涉及盐的字节数组连接在一起时遇到了一些麻烦。我做对了吗,还是有更好的方法?谢谢。

【问题讨论】:

  • 没有使用 MD5 加密密码的好方法。您应该使用 scrypt 或 PBKDF2 散列密码。
  • 无法使用 MD5 对密码进行加密。它是一种单向哈希函数,而不是加密算法。
  • 这里的变化很难跟上。随着更多的计算能力变得可用,破解一些较弱的方法就更容易了。虽然 MD5 在过去就足够了,但有一些更新的方法需要更多的计算能力才能破解。
  • 除了明显错误地选择了 MD5 而不是 PBKDF2、bcrypt 或 scrypt,你的加盐方法也很糟糕。为您的盐使用加密 PRNG,而不是当前时间。
  • 只是重复 SLaks 的观点:单次迭代 SHA-2 与 MD5 一样错误,所以我对所有推荐的答案都投了反对票。

标签: c# encryption passwords md5


【解决方案1】:

我将只将盐值和散列(不是 saltedencryptedPassword)存储在数据库的不同列中,并使用输入的密码重新生成散列。你在这里找到类似的答案Hash and salt passwords in C#.1`

我有时只使用 GUID 作为盐值,然后在散列之前将其添加到密码中。

MD5 不再安全(2004 年被中国人入侵),您可以使用 SHA256 或 SHA512 代替。编辑:但是这些算法的计算速度非常快,因此更容易破解。 @SLaks 建议使用 scrypt 或 PBKDF2,因为它们更难计算。 在Rfc2898DeriveBytes下.NET中有一个PBKDF2的内置实现。

另外一点:我不会每次都创建一个新的 Random() 对象。如果你在短时间内调用它,每次都会生成相同的随机数序列,因为种子值是基于时间的。

【讨论】:

  • 嗯?您还需要存储哈希。另外,不要使用 SHA 作为密码。
  • 当然还有哈希,但不是 saltedEncryptedPassword。在您看来,您应该使用什么作为哈希算法? MD5 不安全,SHA256 慢了 20 倍,但是安全和 RIPEMD160 太慢了。简而言之,对于 C#,SHA256 是要走的路。
  • @slfan RIPEMD160 太快了,不算太慢。密码哈希应该故意慢。
  • "MD5 不再安全(2004 年被中国人入侵)" 迄今为止,针对 MD5 的最佳原像攻击仍然在 2^120 左右。您提到的密码分析主要是关于冲突,而这些与密码哈希完全无关。
  • @CodeInChaos:好点,但 .NET 中只有 4 种哈希算法,而且 RIPEMD160 速度慢,安全性略高于 SHA1。让它变慢的唯一方法是重新散列,但这也不被认为是好的。
【解决方案2】:

密码哈希应该,而不是快。
哈希值越快,攻击者通过密码字典的速度就越快。

因此,您永远不应使用 SHA 等通用哈希作为密码。

改为使用经过验证的慢速技术,例如 scrypt 或 PBKDF2

【讨论】:

  • 谢谢。 (我不知道为什么我等了这么久才回答)
  • 你能给我指出一个解释如何正确实施它的网站吗?我知道谷歌会为我提供多个,我相信你会选择正确的:)
  • This 应该不错,虽然我不能保证。或者带有msdn.microsoft.com/en-us/library/yx129kfs.aspx 的 PBKDF 我可能会说从 10K 迭代开始,如果太慢则减少它。
  • 这是一个虚拟的学校项目,而不是在现实生活中使用。我只是想让概念正确,所以我会使用更少的迭代。谢谢您的帮助!我想使用标准库,所以我会找出如何去做。我需要对密码字符串进行 UTF8 编码吗?
  • ctor 会为你做这件事。
【解决方案3】:

我总是使用 SHA2-512 对我的密码进行散列。在我看来,密码永远不应该被加密,而总是被散列(无法追溯到原始密码)。

但是请不要再使用MD5,现在很容易翻译成密码。

【讨论】:

  • SHA 不应该用于密码。
  • 没有有效的针对 MD5 的前映像攻击。你会攻击一个用 MD5 散列的密码,就像你攻击一个用 SHA-512 散列的密码一样:通过猜测密码
【解决方案4】:

不,这不好。 MD5 已经不行了。它与自己发生冲突,不值得信任。您应该使用 SHA256。

public string getSHA256(string input)
{
    try
    {
        return BitConverter.ToString(SHA256Managed.Create().ComputeHash(Encoding.Default.GetBytes(input))).Replace(“-”, “”).ToLower();
    }
    catch (Exception e)
    {
        return string.Empty;
    }
}

【讨论】:

  • 不,不,不。使用盐。 SHA 太快了。不要吞下异常。
  • @SLaks +1,永远不要吞下异常,更不要捕获System.Exception
  • “太快”怎么样?我不是专家,您能解释一下为什么会出现问题吗?在这个特定的示例中,如果由于某种原因出现问题,我需要返回空字符串,但不记得为什么...... :)
  • @Qmal:SHA 已经过优化,运行速度极快。这意味着攻击者可以在蛮力攻击中每秒尝试数百万个密码。这不好。