Search code examples
asp.netformatpasswordsmembership

ASP.Net Membership saves changed password as plain text even with Hashed passwordFormat set


I'm using the ASP.Net SqlMembershipProvider to manage my users. Here is my config:

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

My problem is this: when I call Membership.CreateUser to create new users, the password is stored in the DB in hashed format with a salt - which is all good. However, when I call Membership.ChangePassword in an admin function, it is storing the password in plain text format. I really cannot understand this behaviour, since the config clearly says "Hashed" and creating a new user creates a hashed password.


Solution

  • Within the ChangePassword() method of the default ASPMembership provider, the password format for an existing user is retrieved from the database and is the format used to encode a new password for an existing user, and not the password format that is set in web.config, which may now specify a different format to use. You can see this for yourself by downloading the source code for the default providers.

    My question is then, is the password being stored in clear text for a user who already had a password stored in clear text? You can check this easily by checking the value of the PasswordFormat field for the user in table aspnet_Membership. The values are:

    Clear = 0,
    Hashed = 1,
    Encrypted = 2,
    

    EDIT :

    if you need to hash clear passwords yourself, the framework code may come in handy

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

    now you just need to pull all records from the database where the PasswordFormat = 0, run them through a console app to hash the password and save the salt, hashed password to the database, as well as update the PasswordFormat field to 1