I'm finding surprisingly little information on converting an existing database from Encrypted passwords to Hashed passwords. (I was able to find a bit more information on converting the other way, but it wasn't of much help.)
As most people know, changing the passwordFormat
setting in web.config only affects new users. I have a database with a couple of hundred users and I'd like to convert them to use hashed passwords without changing those existing passwords.
Is anyone else familiar with how one might approach this? Thanks for any tips.
This is the approach I'd start with to see how far I got:
- Create two MembershipProviders in my web.config, one for encrypted passwords and one for hashed.
- Loop through all users using encrypted password provider. (SqlMembershipProvider.GetAllUsers)
- Get the user's password using encrypted password provider. (MembershipUser.GetPassword)
- Change the user's password to the same password using hashed password provider. (MembershipUser.ChangePassword)
So it'd be something like this:
<membership defaultProvider="HashedProvider">
<providers>
<clear />
<add name="HashedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="false" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Hashed" type="System.Web.Security.SqlMembershipProvider" />
<add name="EncryptedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="true" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Encrypted" type="System.Web.Security.SqlMembershipProvider" />
</providers>
</membership>
code:
SqlMembershipProvider hashedProvider = (SqlMembershipProvider)Membership.Providers["HashedProvider"];
SqlMembershipProvider encryptedProvider = (SqlMembershipProvider)Membership.Providers["EncryptedProvider"];
int unimportant;
foreach (MembershipUser user in encryptedProvider.GetAllUsers(0, Int32.MaxValue, out unimportant ))
{
hashedProvider.ChangePassword(user.UserName, user.GetPassword(), user.GetPassword());
}
Greg's solution is a good start, but it won't affect existing users. The SqlMembershipProvider protects existing users and passwords by storing the PasswordFormat (0=clear, 1=Hashed, 2=Encrypted) in the table along with passwords. Changing the provider password format only affects inserts to the user tables. In order to convert existing users' passwords to Hashed, you have to change the PasswordFormat parameter for each entry. Here is a simple way to do this:
void HashAllPasswords()
{
var clearProvider = Membership.Providers["SqlProvider_Clear"];
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);
}
}
For security reasons, it's definitely the right decision to switch from encrypted passwords to hashes in your database.
Generally to create hashes out of your existing encrypted passwords, you should first decrypt them and then hash them. Be aware that you will loose (when you finally switch) the original passwords. Instead you're going to have a unique fingerprint (hash) of the users passwords.
Think also about using salt for the hashing (defense against rainbow tables etc.) and also have a look in slow hashing algorithms like BCrypt (Codeplex & Article: How To Safely Store A Password) for security reasons instead of fast ones like MD5.
Keep also in mind, that it will be way more effort to switch the hashing algorithm in the future than changing it from ecryption to hash. So you want to do it right the first time ;)
I would caution you against hashing your passwords haphazardly since there are a lot of caveats to that approach. This Blog post about hashing passwords was very insightful to me, and I think that you should read it. Why do you want hashed passwords instead of encrypted?