【问题标题】:Hashing with random salt in c#?在c#中用随机盐散列?
【发布时间】:2016-06-10 06:42:43
【问题描述】:

我在我的 .NET (C#) 客户端中使用 CryptSharp Library 使用随机生成的盐 (Blowfish) 对用户密码进行哈希处理。

然后我继续将散列密码发送到我的远程服务器,并将其存储在 MySQL 数据库中。

当我尝试使用相同的纯文本密码登录时,发送的内容与存储在数据库中的内容之间存在哈希不匹配。 (很可能是因为盐每次都在变化)

我不想向我的 PHP 端发送未加密的纯文本密码,如何在不使用静态盐的情况下实现此目的?

散列(C#):

string passHash = Crypter.Blowfish.Crypt(Password.Text, Crypter.Blowfish.GenerateSalt());

我不希望在注册时创建一个新列来存储客户的盐,但如果我必须这样做。

【问题讨论】:

  • 您为什么使用 Blowfish?还有其他更直接的方法可以直接从 .NET 框架生成散列。那么,您使用 Blowfish 有什么具体原因吗?
  • 如果不是 Bcrypt(Blowfish),你会推荐什么?
  • 使用 .NET 框架中的 SHA1Managed,请参阅下面的答案

标签: c# php hash salt


【解决方案1】:

答案很简单,与所使用的语言无关:

    1234563是盐和迭代次数直接存储在哈希中,因此不需要数据库中的额外列)。
  1. 如果你想给它们加盐,你需要存储一个盐列并将其传输到客户端以在散列期间使用。通常,您将为每个用户使用随机盐,并且仅在更改密码时才会更改。这是推荐但不是必需的 - 它使彩虹表攻击无用。

  2. 如果您担心通过网络传输,而不是特别担心您的数据库,您可以在身份验证期间在服务器上生成一个随机盐,并且只使用一次 - 但服务器将需要原始密码进行比较。

您也可以结合所有这些方法,尽管我认为这不是任何地方的标准做法。

【讨论】:

    【解决方案2】:

    你可以用这个:

    var result = string.Empty;
    using (var sha1 = new SHA1Managed())
    {
        result = ToHex(sha1.ComputeHash(Encoding.ASCII.GetBytes(Password.Text)));
    }
    

    ToHex 看起来像这样:

    public static string ToHex(byte[] bytes)
    {
        return string.Concat(bytes.Select(b => b.ToString("X2")));
    }
    

    前面的代码在多次调用时确实会产生相同的哈希值,而无需涉及盐。

    .NET 框架支持其他更安全的 SHA 算法版本,例如 SHA256Managed。使用 SHA1 或 SHA256 取决于您的安全要求。

    【讨论】:

    • 这是一种极其不安全的密码存储方式,既没有对哈希进行加盐处理,也没有迭代来控制哈希的必要时间。这样的哈希值很容易被暴力破解(大约 5 Giga / sec)。
    【解决方案3】:

    加密密码的目的是将密码安全地存储在数据库中。 CryptSharp 不会帮助您保护网络传输。

    您可以采用多种方法,但最简单的方法可能是通过 SSL 与服务器通信。如果您不想使用公共 CA,请使用自签名证书并挂钩 ServicePointManager.ServerCertificateValidationCallback 以接受您自己的 CA 或证书。

    【讨论】:

      【解决方案4】:

      要将密码从客户端传输到服务器,需要一个加密的 HTTPS/SSL 连接。它会在将用户输入发送到客户端之前对其进行加密,因此 ManInTheMiddle 无法窃听。散列必须在服务器端完成,至少是部分散列。

      CryptSharp 支持通用存储格式,并在生成的哈希中包含盐。不幸的是,似乎没有一种验证方法可以提取用过的盐,至少我找不到。

      我可以推荐的另一个库是BCrypt.Net,salt 也与哈希一起存储(不需要额外的字段),验证非常简单:BCrypt.Verify(password, stored_hash)

      【讨论】: