Changing passwordFormat from Encrypted to Hashed

19,776

Solution 1

This is the approach I'd start with to see how far I got:

  1. Create two MembershipProviders in my web.config, one for encrypted passwords and one for hashed.
  2. Loop through all users using encrypted password provider. (SqlMembershipProvider.GetAllUsers)
  3. Get the user's password using encrypted password provider. (MembershipUser.GetPassword)
  4. 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());
}

Solution 2

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);
    }
}

Solution 3

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 ;)

Share:
19,776

Related videos on Youtube

Jonathan Wood
Author by

Jonathan Wood

Software developer working out of Salt Lake City, UT. Independent consultant as SoftCircuits. Currently looking for new job opportunities. I've published a number of open source libraries for .NET on NuGet and GitHub. Interests include playing bass and guitar and hiking with my dog.

Updated on March 15, 2020

Comments

  • Jonathan Wood
    Jonathan Wood about 4 years

    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.

  • Jonathan Wood
    Jonathan Wood about 13 years
    Thanks for the link, it was an interesting read. That said, no method is 100% secure, and hashing passwords is the current industry standard for password storage. I had set up my site to use encrypted passwords as a convenience to users (I can email it to them), but I got complaints that this posed a risk to my users, especially when they use the same password on multiple sites.
  • Jonathan Wood
    Jonathan Wood about 13 years
    Yes, I understand what hashed passwords are and how you cannot convert from hashed to the original password. And I know I need to decrypt the encrypted passwords and then hash them. What I don't know is how I can do this for all records in a way that will then work with ASP.NET membership. (BTW, doesn't ASP.NET membership use a salt for hashed passwords?)
  • Martin Buberl
    Martin Buberl about 13 years
    ASP.NET membership's default hash algorithm is SHA1 and they use salt encoded as Base64.

Related