在数据库中存储散列密码和salt值的最佳方法 - varchar或binary?

时间:2010-08-02 17:13:01

标签: c# hash password-protection salt

一旦我生成了盐并散列了密码(使用bcrypt等),最好将结果存储为数据库中的字符串或字节数组吗?这两种方式都有什么好处吗?或者这是一个更主观的决定?

3 个答案:

答案 0 :(得分:2)

VARCHAR应该足够了。在我看来,VARCHAR数据将更易于使用并与二进制文件一起使用。

内置的ASP.NET成员资格提供程序还将散列密码存储为VARCHAR字段。

答案 1 :(得分:2)

如果使用VARCHAR,请确保字节是有效字符,或者在保存哈希值和salt之前将字节强制为ASCII。为了使数据损坏更安全,您可能希望在将它们存储在VARCHAR字段中之前对Base64或Hexadecimal中的字节进行编码。

例如,如果您存储MD5SHA1byte[]输出,则byte[]转换为文本时,某些字节值可能会被删除或替换它们不是有效的UTF-8 / Unicode。如果您使用ASCII,这不应该是一个问题,但它仍然可能导致数据损坏。

如果您不想处理Hex,可以使用框架内置的base64方法Convert.ToBase64String

如果您使用VARBINARY并且不尝试使用和文本编码方法,则此问题不应存在,但可能会使哈希比较困难。

...请注意,如果您使用NVARCHAR此数据仍可能发生损坏......

static void Main(string[] args)
{
    var salt = "MySalt";
    var password = "MyPassword";

    var saltedKey = CalculateHash(salt, password);

    Console.WriteLine(saltedKey);
    // MySalt$teGOpFi57nENIRifSW3m1RQndiU=

    var checkHash = CheckHash(saltedKey, password);
    Console.WriteLine(checkHash);
    // True
}

private static string CalculateHash(string saltOrSaltedKey, string password)
{
    var salt =
        saltOrSaltedKey.Contains('$')
        ? saltOrSaltedKey.Substring(0, saltOrSaltedKey.IndexOf('$') + 1)
        : saltOrSaltedKey + '$';

    var newKey = Encoding.UTF8.GetBytes(salt + password);

    var sha1 = SHA1.Create();
    sha1.Initialize();
    var result = sha1.ComputeHash(newKey);

    // if you replace this base64 version with one of the encoding 
    //   classes this will become corrupt due to nulls and other 
    //   control character values in the byte[]
    var outval = salt + Convert.ToBase64String(result);

    return outval;
}

private static bool CheckHash(string saltedKey, string password)
{
    var outval = CalculateHash(saltedKey, password);
    return outval == saltedKey;
}

答案 2 :(得分:1)

大多数md5 / sha1库返回哈希base64编码,在这种情况下varchar就足够了