在 C# 窗体中将密码存储更改为哈希存储
Changing Storage of Password to Storing of Hashes in C# Forms
我当前的项目正在使用 Microsoft 的 Membership 来管理用户的凭据。
目前,它以纯文本形式将密码存储到 SQL 数据库中。
我想改为存储哈希值,或者更改为 encrypt/hide 密码列。
当前代码:
protected void BtnSubmit_Click(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
NAME_OF_TABLE_Provider provider = new NAME_OF_TABLE_Provider();
string userName = SPContext.Current.Web.CurrentUser.Name;
MembershipUserCollection userMembership = Membership.GetAllUsers();
MembershipUser membershipUser = userMembership[userName];
if (membershipUser != null)
{
try
{
membershipUser.ChangePassword(OldPassword.Text, NewPassword.Text);
ConfirmPanel.Visible = true;
InvalidPanel.Visible = false;
Message.InnerText = "The password is changed successfully";
}
catch (Exception ex)
{
ConfirmPanel.Visible = false;
InvalidPanel.Visible = true;
InvalidPassword.InnerText = "The password is not strong. Please verify.";
}
}
}
}
#1 可能的(?)解决方案:HashBytes
INSERT INTO <tbl> (..., passwd) values (...., HashBytes('SHA1', @password))
SELECT HashBytes('SHA1', @password);
#2 可能(?)解决方案:C# 存储哈希
static void Main(string[] args)
{
//Store a password hash:
PasswordHash hash = new PasswordHash("password");
byte[] hashBytes = hash.ToArray();
//For testing purposes
Console.WriteLine(Convert.ToBase64String(hashBytes));
//Check password against a stored hash
byte[] hashBytes2 = hashBytes;//read from store.
PasswordHash hash2 = new PasswordHash(hashBytes2);
if (!hash.Verify("password"))
{
throw new System.UnauthorizedAccessException();
}
else
{
Console.WriteLine("True");
}
Console.ReadLine();
}
}
public sealed class PasswordHash
{
const int SaltSize = 16, HashSize = 20, HashIter = 10000;
readonly byte[] _salt, _hash;
public PasswordHash(string password)
{
new RNGCryptoServiceProvider().GetBytes(_salt = new byte[SaltSize]);
_hash = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
}
public PasswordHash(byte[] hashBytes)
{
Array.Copy(hashBytes, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hashBytes, SaltSize, _hash = new byte[HashSize], 0, HashSize);
}
public PasswordHash(byte[] salt, byte[] hash)
{
Array.Copy(salt, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hash, 0, _hash = new byte[HashSize], 0, HashSize);
}
public byte[] ToArray()
{
byte[] hashBytes = new byte[SaltSize + HashSize];
Array.Copy(_salt, 0, hashBytes, 0, SaltSize);
Array.Copy(_hash, 0, hashBytes, SaltSize, HashSize);
return hashBytes;
}
public byte[] Salt { get { return (byte[])_salt.Clone(); } }
public byte[] Hash { get { return (byte[])_hash.Clone(); } }
public bool Verify(string password)
{
byte[] test = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
for (int i = 0; i < HashSize; i++)
if (test[i] != _hash[i])
return false;
return true;
}
#3 可能(?)解决方案:Transact-SQL 加密单列
请问正确的做法是什么?谢谢。
不言而喻,任何解决方案都比当前解决方案更好。
第一个解决方案看起来很可靠,但我无法确定是否使用了盐。如果没有,那就是劣势。您现在也依赖于此数据库供应商,无法切换。
第二个解决方案看起来不错,但我没有仔细看,您可能应该前往 CodeReview,他们会审查工作代码以寻求改进。
最后的解决方案不是真正的解决方案。密码 hashed 而不是 exncrypted 是有原因的。如果 you 可以解密它们,那么访问系统并窃取它们的攻击者将与您一样获得解密手段。所以这是一层不便,而不是安全。
所以选择第二个,让别人检查它是否存在弱点或错误。
我当前的项目正在使用 Microsoft 的 Membership 来管理用户的凭据。
目前,它以纯文本形式将密码存储到 SQL 数据库中。
我想改为存储哈希值,或者更改为 encrypt/hide 密码列。
当前代码:
protected void BtnSubmit_Click(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
NAME_OF_TABLE_Provider provider = new NAME_OF_TABLE_Provider();
string userName = SPContext.Current.Web.CurrentUser.Name;
MembershipUserCollection userMembership = Membership.GetAllUsers();
MembershipUser membershipUser = userMembership[userName];
if (membershipUser != null)
{
try
{
membershipUser.ChangePassword(OldPassword.Text, NewPassword.Text);
ConfirmPanel.Visible = true;
InvalidPanel.Visible = false;
Message.InnerText = "The password is changed successfully";
}
catch (Exception ex)
{
ConfirmPanel.Visible = false;
InvalidPanel.Visible = true;
InvalidPassword.InnerText = "The password is not strong. Please verify.";
}
}
}
}
#1 可能的(?)解决方案:HashBytes
INSERT INTO <tbl> (..., passwd) values (...., HashBytes('SHA1', @password))
SELECT HashBytes('SHA1', @password);
#2 可能(?)解决方案:C# 存储哈希
static void Main(string[] args)
{
//Store a password hash:
PasswordHash hash = new PasswordHash("password");
byte[] hashBytes = hash.ToArray();
//For testing purposes
Console.WriteLine(Convert.ToBase64String(hashBytes));
//Check password against a stored hash
byte[] hashBytes2 = hashBytes;//read from store.
PasswordHash hash2 = new PasswordHash(hashBytes2);
if (!hash.Verify("password"))
{
throw new System.UnauthorizedAccessException();
}
else
{
Console.WriteLine("True");
}
Console.ReadLine();
}
}
public sealed class PasswordHash
{
const int SaltSize = 16, HashSize = 20, HashIter = 10000;
readonly byte[] _salt, _hash;
public PasswordHash(string password)
{
new RNGCryptoServiceProvider().GetBytes(_salt = new byte[SaltSize]);
_hash = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
}
public PasswordHash(byte[] hashBytes)
{
Array.Copy(hashBytes, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hashBytes, SaltSize, _hash = new byte[HashSize], 0, HashSize);
}
public PasswordHash(byte[] salt, byte[] hash)
{
Array.Copy(salt, 0, _salt = new byte[SaltSize], 0, SaltSize);
Array.Copy(hash, 0, _hash = new byte[HashSize], 0, HashSize);
}
public byte[] ToArray()
{
byte[] hashBytes = new byte[SaltSize + HashSize];
Array.Copy(_salt, 0, hashBytes, 0, SaltSize);
Array.Copy(_hash, 0, hashBytes, SaltSize, HashSize);
return hashBytes;
}
public byte[] Salt { get { return (byte[])_salt.Clone(); } }
public byte[] Hash { get { return (byte[])_hash.Clone(); } }
public bool Verify(string password)
{
byte[] test = new Rfc2898DeriveBytes(password, _salt, HashIter).GetBytes(HashSize);
for (int i = 0; i < HashSize; i++)
if (test[i] != _hash[i])
return false;
return true;
}
#3 可能(?)解决方案:Transact-SQL 加密单列
请问正确的做法是什么?谢谢。
不言而喻,任何解决方案都比当前解决方案更好。
第一个解决方案看起来很可靠,但我无法确定是否使用了盐。如果没有,那就是劣势。您现在也依赖于此数据库供应商,无法切换。
第二个解决方案看起来不错,但我没有仔细看,您可能应该前往 CodeReview,他们会审查工作代码以寻求改进。
最后的解决方案不是真正的解决方案。密码 hashed 而不是 exncrypted 是有原因的。如果 you 可以解密它们,那么访问系统并窃取它们的攻击者将与您一样获得解密手段。所以这是一层不便,而不是安全。
所以选择第二个,让别人检查它是否存在弱点或错误。