我正在使用ASP.Net SqlMembershipProvider来管理我的用户。这是我的配置:
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add
name="SqlProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="SiteDatabase"
applicationName="WPR"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="true"
passwordFormat="Hashed" />
</providers>
</membership>
我的问题是:当我调用Membership.CreateUser来创建新用户时,密码以散列格式存储在数据库中,并带有一个盐 - 这一切都很好。但是,当我在管理功能中调用Membership.ChangePassword时,它以纯文本格式存储密码。我真的无法理解这种行为,因为配置清楚地说“Hashed”并且创建新用户会创建一个哈希密码。
答案 0 :(得分:6)
在默认ASPMembership提供程序的ChangePassword()
方法中,从数据库中检索现有用户的密码格式,该格式是用于为现有用户编码新密码的格式,而不是密码格式在web.config
中设置,现在可以指定要使用的其他格式。您可以通过downloading the source code for the default providers自行查看。
我的问题是,对于已经以明文形式存储密码的用户,密码是否以明文形式存储?您可以通过检查表aspnet_Membership
中用户的PasswordFormat字段的值来轻松检查此问题。值为:
Clear = 0,
Hashed = 1,
Encrypted = 2,
编辑:
如果您需要自己散列清除密码,框架代码可能会派上用场
// generate a salt
public string GenerateSalt()
{
byte[] buf = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
// hashes the password, using the supplied salt
public string HashPassword(string pass, string salt)
{
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bAll = new byte[bSalt.Length + bIn.Length];
byte[] bRet = null;
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
// this assumes a Hashed password (PasswordFormat = 1)
HashAlgorithm s = HashAlgorithm.Create( Membership.HashAlgorithmType );
bRet = s.ComputeHash(bAll);
return Convert.ToBase64String(bRet);
}
现在您只需从PasswordFormat = 0的数据库中提取所有记录,通过控制台应用程序运行它们以散列密码并将salt,哈希密码保存到数据库,以及将PasswordFormat字段更新为1
答案 1 :(得分:1)
为此,我使用控制台应用程序。我直接在数据库中更改了PasswordFormat
表中的aspnet_Membership
。然后,我借助ResetPassword
和ChangePassword
方法将密码更改为相同的密码。此外,如果用户被锁定,我会在更改密码之前将其解锁,然后再次锁定。在app.config文件中,我有数据库模型和成员资格提供程序的连接字符串,以及成员资格提供程序定义。
请注意,如果旧密码不符合提供商设置中的最新密码要求,则ChangePassword
方法将失败。
代码如下:
static void Main(string[] args)
{
using (var db = new MyEntities())
{
var usersToFix = db.aspnet_Membership.Where(x => x.PasswordFormat == 0).ToList();
foreach (var userToFix in usersToFix)
{
userToFix.PasswordFormat = 1;
var password = userToFix.Password;
var passwordQuestion = userToFix.PasswordQuestion;
var passwordAnswer = userToFix.PasswordAnswer;
var lastLockoutDate = userToFix.LastLockoutDate;
db.SaveChanges();
var user = Membership.GetUser(userToFix.UserId);
bool locked = user.IsLockedOut;
if (locked)
{
user.UnlockUser();
}
var resetPassword = user.ResetPassword();
user.ChangePassword(resetPassword, password);
user.ChangePasswordQuestionAndAnswer(password, passwordQuestion, passwordAnswer);
if (locked)
{
userToFix.IsLockedOut = true;
userToFix.LastLockoutDate = lastLockoutDate;
db.SaveChanges();
}
Console.WriteLine("{0} - OK", user.UserName);
}
}
Console.WriteLine("Done!");
Console.ReadKey();
}
答案 2 :(得分:0)
Russ的解决方案可能有效,但如果所有现有用户都拥有明确或加密的密码,则可以采用更简单的方法。在web.config中设置2个sql成员资格提供程序,一个使用明确(或加密)密码,另一个使用散列。然后在Web应用程序中的某处执行此代码:
void ConvertPasswordsToHashed()
{
var clearProvider = Membership.Providers["SqlProvider"];
var hashedProvider = Membership.Providers["SqlProvider_Hashed"];
int dontCare;
if (clearProvider == null || hashedProvider == null) return;
var passwords = clearProvider.GetAllUsers(0, int.MaxValue, out dontCare)
.Cast<MembershipUser>().ToDictionary(u => u.UserName, u => u.GetPassword());
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings[0].ConnectionString))
{
conn.Open();
using (var cmd = new SqlCommand("UPDATE [aspnet_Membership] SET [PasswordFormat]=1", conn))
cmd.ExecuteNonQuery();
}
foreach (var entry in passwords)
{
var resetPassword = hashedProvider.ResetPassword(entry.Key, null);
hashedProvider.ChangePassword(entry.Key, resetPassword, entry.Value);
}
}