我最近在我正在进行的项目中为我的密码实施了Hashing,我似乎无法弄清楚出了什么问题。
似乎HashPasswordForStoringInConfigFile()函数为同一密码返回不同的值。
我实现了以下代码,它实际上非常类似于在MSDN文档中使用的推荐算法。
我知道SHA1散列不被认为是非常安全的,但这是一个研究应用程序,我现在不太担心它。
public const int DefaultSaltSize = 5;
private static string CreateSalt()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buffer = new byte[DefaultSaltSize];
rng.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
public static string CreateHash(string password)
{
string salt = CreateSalt();
string saltAndPassword = String.Concat(password, salt);
string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword,"SHA1");
hashedPassword = string.Concat(hashedPassword,salt);
return hashedPassword;
}
public static bool VerifyPassword(string username, string password,AccountDataContext context)
{
var user = context.UserAccounts.FirstOrDefault(p => p.UserName == username);
if (user != null)
{
string salt = user.Password.Substring(user.Password.Length - DefaultSaltSize);
string hashedPassword = CreateHash(password);
return hashedPassword.Equals(user.Password);
}
return false;
}
简单地说,如果我有以下代码。
string password1 = "password";
string password2 = "password";
var hashedPassword1 = CreateHash(password1);
var hashedPassword2 = CreateHash(password2);
var match = hashedPassword1.Equals(hashedPassword2);
//match should be True, but it is turning out False.
似乎FormsAuthenticationForStoringInConfigFile()没有在CreateHash()方法中为password1和password2返回相同的哈希值。
我理解使用盐它们不一样,但是如果你在代码中看到,我在删除盐之前比较两个hashedPasswords是否相等。
什么可能导致密码1和密码2被散列不同?
答案 0 :(得分:4)
您的代码在散列之前已将密码(随机值)添加到密码中。这是一件好事。
这意味着如果用户A和用户B使用相同的密码,密码哈希值将会不同。
您的VerifyPassword方法未使用原始哈希值来比较密码 - 而是调用CreateHash
,调用CreateSalt
并创建新的盐。
您可以尝试以下方式:
public static string CreateHash(string password)
{
return CreateHash(password, CreateSalt());
}
private static string CreateHash(string password, string salt)
{
string saltAndPassword = String.Concat(password, salt);
string hashedPassword =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPassword,"SHA1");
hashedPassword = string.Concat(hashedPassword,salt);
return hashedPassword;
}
public static bool VerifyPassword(string username,
string password,AccountDataContext context)
{
var user = context.UserAccounts.FirstOrDefault(p => p.UserName == username);
if (user != null)
{
string salt = user.Password.Substring(user.Password.Length - DefaultSaltSize);
string hashedPassword = CreateHash(password, salt);
return hashedPassword.Equals(user.Password);
}
return false;
}
答案 1 :(得分:1)
即使VerifyPassword看起来像是剥离了未散列字符串的salt部分,但是你说的代码应该返回true并不会实际调用VerifyPassword。
您的代码只生成两个盐渍哈希值,然后使用String.Equals来比较它们。
使用VerifyPassword而不是String.Equals会发生什么?
答案 2 :(得分:0)
此代码根本不起作用。为什么它被标记为正确答案?
Salt的默认长度设置为5
当一个字符串需要5个字节的数组时,创建Salt,它变为8个字符而不是5个
验证密码然后只关闭5个字符,因为盐不是8,因此验证将始终失败,因为它使用盐的5个字符而不是用于创建哈希密码的8个字符。
以下是更新代码,以使上述代码有效。
private const int DEFAULT_SALT_SIZE = 5;
private static string CreateSalt()
{
RNGCryptoServiceProvider rngCryptoServiceProvider = new RNGCryptoServiceProvider();
byte[] buffer = new byte[DEFAULT_SALT_SIZE];
rngCryptoServiceProvider.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
public static string CreateHash(string password)
{
return CreateHash(password, CreateSalt());
}
private static string CreateHash(string password, string salt)
{
string saltAndPassword = String.Concat(password, salt);
string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1");
hashedPassword = string.Concat(hashedPassword, salt);
return hashedPassword;
}
public static bool VerifyPassword(string userpassword, string password)
{
byte[] bytePassword = Convert.FromBase64String(userpassword);
byte[] byteSalt = new byte[DEFAULT_SALT_SIZE];
Array.Copy(bytePassword, bytePassword.Length - DEFAULT_SALT_SIZE, byteSalt, 0, DEFAULT_SALT_SIZE);
string salt = Convert.ToBase64String(byteSalt);
string hashedPassword = CreateHash(password, salt);
return hashedPassword.Equals(userpassword);
}
这就是我所说的。
string hashedPassword = Security.CreateHash("password");
if (Security.VerifyPassword(hashedPassword, "password"))
{
Response.Write("Valid");
}
else
{
Response.Write("Not Valid");
}
只要密码匹配就返回true,否则返回false。
这给了你我认为的目的,不仅是在哈希中包含salt而且还将它添加到哈希的外部,这样它们就可以作为1列值存储在数据库中然后用于使用存储的salt值重新创建用户输入密码的哈希并获得匹配。