简体   繁体   中英

Best way to store hashed passwords and salt values in the database - varchar or binary?

Once I've generated a salt and hashed the password (using bcrypt, etc) would it be best to store the results as a string or as a byte array in the database? Are there any benefits either way? Or is it a more subjective decision?

VARCHAR should be sufficient. In my opinion VARCHAR data will be easier to consume and work with vs. binary.

The built in ASP.NET membership providers also store hashed passwords as VARCHAR fields.

If you use VARCHAR either make sure the bytes are either valid characters or force the bytes to ASCII before you save the hash and salt. To make is safer from data corruption you may want to either encode the bytes in Base64 or Hexadecimal before you store them in the VARCHAR field.

For example, if you store the byte[] output from MD5 or SHA1 some of the byte values may be removed or replaced when the byte[] is converted to text is they are not valid UTF-8/Unicode. This should not be as much of a problem if you are using ASCII but it could still cause data corruption.

If you don't want to deal with Hex you could use this base64 method Convert.ToBase64String that is built into the framework.

If you use VARBINARY and don't try to use and text encoding methods this issue should not exist, but could make comparing hashes more difficult.

...Note that if you use NVARCHAR this data corruption could still occur...

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;
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM