我遇到过这篇文章,它描述了在数据库中存储“未加盐”密码哈希的危险,可能会使用所谓的“彩虹表”进行逆向工程。
它还附带这个C# 代码示例,基本上需要在您的用户密码数据库表中存储两个哈希列(而不是传统的 - 一个。)对我来说这种方法的问题是我已经建立了一个带有未加盐用户密码的数据库表散列,添加新列将需要重组数据库。所以在我这样做之前,我一直在寻找一个不同的选择,这就是我想出的。
这是一个函数,它不是简单地计算密码上的 SHA1 哈希,而是用一长串伪随机(但一致)数据填充它,然后计算哈希:
byte[] computeSecureHash(string strUserPassword)
{
//RETURN: = SHA1 byte array on the 'strUserPassword'
//Make simple junk array based on the password
ushort v = 117;
byte[] arrJunk = new byte[24];
for (int c = 0, i = 0; i < arrJunk.Length; i++)
{
v ^= strUserPassword[c++];
v *= 7;
arrJunk[i] = (byte)v;
if (c >= strUserPassword.Length)
c = 0;
}
//Make crypto byte array based on the password
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(strUserPassword, arrJunk);
pbkdf2.IterationCount = 1000;
byte[] arrCrypto = pbkdf2.GetBytes(128);
//Pad actual password
string strUserPassword_Padded = "";
const string strChars2Use = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`-=[]\\;',./~!@#$%^&*()_+{}|:\"<>?";
int nHalfArrCrypto = arrCrypto.Length / 2;
//Left side
for (int i = 0; i < nHalfArrCrypto; i++)
{
strUserPassword_Padded += strChars2Use[arrCrypto[i] % strChars2Use.Length];
}
strUserPassword_Padded += strUserPassword;
//Right side
for (int i = nHalfArrCrypto; i < arrCrypto.Length; i++)
{
strUserPassword_Padded += strChars2Use[arrCrypto[i] % strChars2Use.Length];
}
//For user's password "123"
//the 'strUserPassword_Padded' becomes:
//"bwDR]_B>H5t-k:eIq?r_wGBWqWfs#tcAE~DQ5?(Pbj#<+Cw:9(r!B[f_.S<pCjn-123b9l3<Sz^D~>G}v)?NuHT4BZ-pI2$W[kW1e4KO\"`rTg3H`}&jmtrFh1J5c72:})tQ"
//And now compuse SHA1 on the padded password
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] bytesInputData = System.Text.Encoding.UTF8.GetBytes(strUserPassword_Padded);
return sha1.ComputeHash(bytesInputData);
}
所以我的问题是,有人可以查看这段代码并告诉我这样做的危险与作者在他的代码中所建议的相比有什么危险吗?对于我的代码示例,我只需要在数据库中存储一个散列而不是两个(密码散列 + 盐散列。)