在过去处理密码时,我总是在我的数据存储中分别存储盐和散列密码。今天我想更新一些遗留代码以使用RFC 2898哈希值。我发现了来自Crypto.Hash
的{{1}}方法。看起来这些将为我完成大部分繁重的工作。有System.Web.Helpers
,GenerateSalt()
和HashPassword()
方法。 VerifyHashedPassword()
和HashPassword()
方法不带盐值。 VerifyHashedPassword()
方法的MSDN文档说:
“生成的哈希字节流的格式为{0x00,salt,subkey},在返回之前进行base-64编码。”
我需要担心盐吗?文档似乎说会自动生成一个salt并存储在base-64编码值中?它是否正确?我需要存储的是从HashPassword()
返回的字符串?
答案 0 :(得分:51)
所有密码都需要加密,以便安全地哈希。但是,在这种情况下,你是对的。 System.Web.Helpers.Crypto负责为您创建一个salt。 您不需要创建一个。它存储在Crypto.HashPassword()返回的字符串中。
你需要做的就是这样。
using System.Web.Helpers;
public void SavePassword(string unhashedPassword)
{
string hashedPassword = Crypto.HashPassword(unhashedPassword);
//Save hashedPassword somewhere that you can retrieve it again.
//Don't save unhashedPassword! Just let it go.
}
public bool CheckPassword(string unhashedPassword)
{
string savedHashedPassword = //get hashedPassword from where you saved it
return Crypto.VerifyHashedPassword(savedHashedPassword, unhashedPassword)
}
答案 1 :(得分:-2)
只是想分享这篇文章:
http://forums.asp.net/t/1842429.aspx?System+Web+Helpers+Crypto+HashPassword
您好,
我一直在查看System.Web.Helpers中新的Crypto HashPassword和VerifyMethod方法。
这两种方法都使用Salt,但它们不会仅使用Hash返回Salt 我不需要Salt将其存储在数据库中吗?我错过了什么吗? 谢谢,
米格尔
...
您在用户创建帐户时生成salt,然后生成 您在调用HashPassword之前将其附加到密码。你' d 然后在您的数据库中存储该salt和哈希密码。当你 验证凭据只需从数据库中读取盐并将其附加到 在调用VerifyHashedPassword之前登录的密码。 BrockAllen
...
不确定我是否理解...因为在HashPassword中,盐是 在方法内部生成:
米格尔
// Method in Crypto class
public static string HashPassword(string password)
{
if (password == null)
{
throw new ArgumentNullException("password");
}
// Produce a version 0 (see comment above) password hash.
byte[] salt;
byte[] subkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
{
salt = deriveBytes.Salt;
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
byte[] outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
return Convert.ToBase64String(outputBytes);
}
...
BrockAllen 2012年9月11日下午07:50
是的,忽略它 - 它是Rfc2898DeriveBytes的内部盐 并且它来自密码,所以它不是真正的盐 存储密码的上下文,因为它一直在重新创建 相同的密码。你会想要自己做自己的盐 密码字符串级别。所以像这样:
public void CreateAccount(string username, string password)
{
var salt = Crypto.GenerateSalt();
var saltedPassword = password + salt;
var hashedPassword = Crypto.HashPassword(saltedPassword);
CreateAccount(username, salt, hashedPassword);
}
public void Verify(string username, string password)
{
var salt = GetSaltForUserFromDatabase(username);
var hashedPassword = GetHashedPasswordForUserFromDatabase(username);
var saltedPassword = password + salt;
if (Crypto.VerifyHashedPassword(hashedPassword, saltedPassword))
{
// valid password for this username
}
}
这将允许您将盐与散列盐渍密码一起存储在数据库中。
此帖子中有关使用salt进行密码哈希的其他信息: https://crackstation.net/hashing-security.htm
存储密码
验证密码
加密类的源代码:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Helpers/Crypto.cs