我正在接管前一位开发人员写的系统。系统有管理员批准用户帐户,当他们这样做时,系统使用以下方法来散列密码并将其保存到数据库。它将未散列的密码发送给用户。当用户登录系统时,使用完全相同的方法来散列用户输入的内容并将其与数据库值进行比较。当数据库条目与用户输入的内容不匹配时,我们会遇到几次。所以看起来该方法并不总是散列值相同。有谁知道这种散列方法是否不可靠以及如何使其可靠?感谢。
private string HashPassword(string password)
{
string hashedPassword = string.Empty;
// Convert plain text into a byte array.
byte[] plainTextBytes = Encoding.UTF8.GetBytes(password);
// Allocate array, which will hold plain text and salt.
byte[] plainTextWithSaltBytes =
new byte[plainTextBytes.Length + SALT.Length];
// Copy plain text bytes into resulting array.
for(int i = 0; i < plainTextBytes.Length; i++)
plainTextWithSaltBytes[i] = plainTextBytes[i];
// Append salt bytes to the resulting array.
for(int i = 0; i < SALT.Length; i++)
plainTextWithSaltBytes[plainTextBytes.Length + i] = SALT[i];
// Because we support multiple hashing algorithms, we must define
// hash object as a common (abstract) base class. We will specify the
// actual hashing algorithm class later during object creation.
HashAlgorithm hash = new SHA256Managed();
// Compute hash value of our plain text with appended salt.
byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);
// Create array which will hold hash and original salt bytes.
byte[] hashWithSaltBytes = new byte[hashBytes.Length +
SALT.Length];
// Copy hash bytes into resulting array.
for(int i = 0; i < hashBytes.Length; i++)
hashWithSaltBytes[i] = hashBytes[i];
// Append salt bytes to the result.
for(int i = 0; i < SALT.Length; i++)
hashWithSaltBytes[hashBytes.Length + i] = SALT[i];
// Convert result into a base64-encoded string.
hashedPassword = Convert.ToBase64String(hashWithSaltBytes);
return hashedPassword;
}
答案 0 :(得分:4)
此函数使用salt 散列。这是一种技术,可以确保它为相同的密码产生不同的哈希,并使表查找更加困难。
只有当具有相同的盐值时,哈希才是相同的。
有关此技术的详细信息,请参阅维基百科http://en.wikipedia.org/wiki/Salt_%28cryptography%29。
引用http://msdn.microsoft.com/en-us/magazine/cc164107.aspx:
要减慢攻击速度,请使用盐。 Salt是一种调整密码的方法 在哈希之前,制作它们 攻击者的预计算字典 无用。这是它的完成方式。 每当你添加一个条目 数据库,你随机计算 用作盐的数字串。 当你想要计算哈希值时 爱丽丝的密码,你抬头看看盐 Alice的帐户的值,前置它 密码,并哈希他们 一起。结果数据库看起来 像这样:
<users> <user name='Alice' salt='Tu72*&' password='6DB80AE7...'/> <user name='Bob' salt='N5sb#X' password='096B1085...'/> <user name='Fred' salt='q-V3bi' password='9118812E...'/> </users>
请注意,现在没有办法说出来 Bob和Fred正在使用相同的东西 密码。注意盐本身 不是秘密。
答案 1 :(得分:1)
如果程序没有使用任何随机决策(也就是说,它是完全确定的),并且使用的算法的实现是相同的(它们应该是 - SHA256应该在任何地方完全相同,并且对于Base64字符串来说也是如此),那么算法本身“不会对值进行相同的散列”是非常不可能的。
如果你无法重现错误(意思是:找到一些在服务器上进行散列时总产生一个散列的值,另一个在客户端进行散列时产生的散列值),则应确保正确地传输和接收这些值。也许客户端获得了未加密的密码?也许服务器正在从客户端接收损坏的数据?也许服务器数据库本身的数据有所改变? 确保每个事务都经过验证,即用户无法收到损坏的密码。