代码之家  ›  专栏  ›  技术社区  ›  Andy Evans

健全性检查:Salt和散列密码

  •  5
  • Andy Evans  · 技术社区  · 15 年前

    我想到了散列密码和salt值。因为我对散列和加密比较陌生,所以我想我应该把这个贴给你。为每个用户帐户生成一个唯一的salt,然后将salt和散列值存储在数据库中会更安全吗?或者,安全地保存一个salt值,并在每次我散列密码时重复使用它?

    例如, 用户将使用密码:

    "secret"
    

    我的代码将生成一个salt值:

    "d1d0e3d4b3d1ed1598a4e77bb614750a2a175e"
    

    然后对结果进行哈希运算,得到:

    "e8187dcbe8e2eabd4675f3a345fe21c98affb
     5544a9278461535cb67265b6fe09a11dbef572
     ce3a4a8f2275839927625cf0bc7bc46fc45d51
     12d7c0713bb4a3"
    

    散列结果和salt将在创建用户帐户时存储在用户配置文件的数据库中。然后,每次用户登录时,都会生成一个新的salt,密码和salt会被重新刷新并存储在数据库中。

    有什么想法吗?就像我说的,这是对我的一个想法的理智检查。

    4 回复  |  直到 15 年前
        1
  •  7
  •   LukeH    15 年前

    在我看来,为每个用户储存一种独特的盐是个好主意。在用户每次登录时重新生成salt/hash组合是没有意义的,除非您需要消耗CPU周期。我建议使用类似 Rfc2898DeriveBytes 类以生成安全的salt/hash组合:

    string password = GetPasswordFromInput();
    
    using (var deriveBytes = new Rfc2898DeriveBytes(password, 32))  // 32-byte salt
    {
        byte[] salt = deriveBytes.Salt;
        byte[] hash = deriveBytes.GetBytes(32);  // 32-byte hash
        SaveToDatabase(salt, hash);
    }
    

    string password = GetPasswordFromInput();
    byte[] salt = GetSaltFromDatabase();
    byte[] hash = GetHashFromDatabase();
    
    using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
    {
        if (deriveBytes.GetBytes(32).SequenceEqual(hash))
            Console.WriteLine("Password matches");
        else
            throw new Exception("Bad password");
    }
    
        2
  •  5
  •   Thorarin    15 年前

    正如Adam已经提到的,每次用户登录时散列和存储密码并没有真正的意义。

    与其自己滚动,不如考虑使用 BCrypt.NET

    用法非常简单:

    // When setting password
    string hashedPassword = BCrypt.HashPassword(password, BCrypt.GenerateSalt());
    
    // Upon login
    bool validPassword = BCrypt.CheckPassword(password, hashedPassword);
    

    如果您愿意,它允许您改变计算密码散列的计算成本,这使得某些人更难对他们可能获得的数据库进行字典攻击。这是通过向 GenerateSalt 方法调用。

    BCrypt算法的细节 can be found here .

        3
  •  3
  •   Rich Adams    15 年前
    • 在用户每次登录时更新salt是没有意义的,这对于安全性没有真正的意义。
    • salt应该是随机生成的,而不是以任何方式与密码链接。

    salt的目的是防止预计算攻击(如彩虹表)。因此,如果两个用户有相同的密码,他们就不会有相同的最终哈希。如果salt是系统范围的,而不是每个用户,那么情况就不会是这样,攻击者只需预先计算一次系统的所有密码。如果每个用户都有自己的salt,则需要对每个用户分别进行预计算攻击,从而使攻击不可行。

    使用salted hash不能防止暴力字典攻击。您需要使用其他方法来防止这些。

        4
  •  1
  •   Hut8    15 年前

    如果你相信有人真的会把你的一个salt的预计算表建立到一个密码数据库中,然后用这个表查找他们在你的数据库中找到的salt密码哈希,那么你应该为每个密码使用一个唯一的salt。否则,不用担心。