Link to home
Start Free TrialLog in
Avatar of Brian
BrianFlag for United States of America

asked on

Password Policy's

Hello Experts,

I would like to have a password policy for users stored passwords. I have all users passwords Salted + Hashed along with a Secret Salt thanks to a friend from EE who helped me out with that. I would like to take it one step further though. I would like to have the current users in my DB to have their password need to be reset/changed every 90 days. I don't know what method would be best to handle this task. I could use the email address that is stored with their profile to send them an email to reset their password before 90 days but not sure how I would use a date to go by.
Avatar of Frosty555
Frosty555
Flag of Canada image

The easiest thing to do is simply store the date that the password was last changed in a field in your "Users" table. You can keep track of the difference in time that way and send reminder emails, but my suggestion is to remind the user at the moment they are logging in. A week before the password expires, after they type their password to log in pop up a box that says "You must change your password in XX days. Change it now?". When the password has expired, have the popup box say "You must change your password before you can login. Change it now?".

If you want to futureproof this design, you can have a separate "password change history" table which stores all of the user's passwords, schema something like this:

PASSWORDHISTORY
      char        passwordmd5hash
      datetime  datechanged
      int            userid

By adding to this table every time the user changes their password, you can maintain a history of passwords and prevent the user from changing their password back to something they used in the past. You can also authenticate the user by testing against the most recent password in the table for that user.
Avatar of gery128
I can think of this simplest approach:

-Add one column 'LastPasswordChangeDate' and whenever user changes password update it with that current datetime.
-Then you have Password change date with you for each user, now you can achieve password reset/change in two different methods:
1) you need to check 'LastPasswordChangeDate' and compare with current date to determine password change days are 90 or more and display appropriate message to user for that at the time of login.
2) you can run a piece of code everyday to determine list of users whose password change days are 90 or more and send them emails / reset their password accordingly.
To setupt he expiry days for passwowrd
Group Policy > User Settings > Security Settings > Account Policies > Password Policy > Maximum Password Age

To setup the password policy here as you like...
Computer Configuration\Windows Settings\Local Policies\Security Options under Interactive Logon: Prompt user to change password before expiration

WHen evern users logon, if the password is going to expire, windows automatically alert the user to change their password...
Frosty555 has suggested similar approach. I would like to add one more thing, you can set public constant in common library to access Password Change Days (i.e. 90 or 30) this way you will have to change only one value at one place or you can store this in sql table also.
@Murali1984
This question is of asp.net web application users' password policy and not of Windows OS.
Avatar of Brian

ASKER

@Frosty555 and gery128:

Should I start by adding a field in my DB called "users_password_date"? Then everytime the password gets changed then I update that field using the SQL getDate() function in SQL?

Also, when I signup users should I use the getDate() function in SQL to set the Date that the user row was created?

Also, should I have code in Page_Load that checks the User when he/she logs in against Today's Date and the value for users_password_date?

What I don't understand is how I can lock the appication down until user changes his/her password if it goes past 90 days.
The field name may differ according to programmer: you can create one like "users_password_date" or "change_password_date" it depends on you. Yes, you need to update this field each time user changes password.

You can use getDate() function to insert the date in user row for field say "user_registration_date" (example)

Ideally, you should check if user's password is older than 90 days and do not authenticate user(i.e. by creating auth cookie/ticket in formsauthenctication or using windows authentication), instead redirect them to the Change Password page on login. So you only need to place this check on login event. Not on every page.

If you implement above check, then user would be redirected to "Change Password" page automatically, so he won't be able to log on to system until he changes his password.
Hello asp_net2, I have made this class for your, this will help you to check the complexity required in your passwords, copy the PasswordPolicy class to a new file in your App_Code folder:
public static class PasswordPolicy
{
    // Settings
    const int MinRequiredPasswordLength = 7;
    const bool MinRequiredAtLeastOneLetter = true;
    const bool MinRequiredAtLeastOneDigit = true;
    const int MinRequiredNonAlphanumericCharacters = 0;// <-- If you set it to one or more can be anoying for some users, but it will increase the password security.

    public static void CheckPassword(string password)
    {
        // Check length
        if (string.IsNullOrEmpty(password) || password.Length < MinRequiredPasswordLength)
            throw new PasswordPolicyException("The password is too short, must be at least " + MinRequiredPasswordLength + " characters long.");

        int letterCount = 0;
        int digitCount = 0;
        int nonAlphanumericCharacterCount = 0;
        foreach (char c in password)
        {
            if (char.IsLetter(c))
                letterCount++;

            if (char.IsDigit(c))
                digitCount++;

            if (!char.IsLetterOrDigit(c))
                nonAlphanumericCharacterCount++;
        }

        // Check if at least a letter is required
        if (MinRequiredAtLeastOneLetter && letterCount == 0)
            throw new PasswordPolicyException("The password must contain at least one letter.");

        // Check if at least a digit is required
        if (MinRequiredAtLeastOneDigit && digitCount == 0)
            throw new PasswordPolicyException("The password must contain at least one decimal digit.");

        // Check if special characters are required (everything that is not a letter or digit)
        if (nonAlphanumericCharacterCount < MinRequiredNonAlphanumericCharacters)
            throw new PasswordPolicyException("The password must contain at least " + MinRequiredNonAlphanumericCharacters + " special character.");
    }

    public class PasswordPolicyException : Exception
    {
        public  PasswordPolicyException() { }
        public  PasswordPolicyException(string message) : base(message) { }
    }
}

Open in new window

The code above can also be accomplished with regular expressions but I have made it in this way to make it easy to understand for you.


How to use? before you save a new password for an user, example:
try
{
    PasswordPolicy.CheckPassword(TextBoxMyPassword.Text);
}
catch (PasswordPolicy.PasswordPolicyException ex)
{
    // Display this error to your user
    MyLabel.Text = ex.Message;
    return; //<-- Important
}

... Here code that save the new password to your DB....

Open in new window


And about password expiring policy's I recommend to follow Frosty555 recommendations (comment 37062738), but remember that your hash is saved as bytes, so the table structure that he recommend must be like:
PasswordHistory
      UserId int
      DateChanged datetime
      PasswordHash binary(96)

Open in new window

Avatar of Brian

ASKER

Hi yv989c,

Thanks for replying. I'm a little confused of course. Is the first code snippet above that you posted for Checking the Password strenght itself only? If so, do I need to tie that in to my creation of a new user? I was planning on using regular expressions using AJAX to control the password strength but I also like your solution as well.

Also, I'm not sure if this is oky to do but I added another field in my table called "users_password_date" which is tied to SQL (getDate()) function. So if a user would change his/her password then it would change the users_password_date to the current data it was changed without user adding the date.

Also, I don't understand Frosty555's method but I do like gery128 method in post 37069710.
Avatar of Brian

ASKER

@gery128,

I like your method from post 37069710. However, I'm not sure how I would check against the date in the DB to current date using FormsAuthentication. Can you be a little more specific since I don't understand?

I had alot of help from yv989c in regards to Salt + Hash my password and then authenticate against that so I'm a little confused how I would use your method for FormsAuthentication to the code below that i'm using for authentication.

    private bool IsValidPassword(string userName, string password)
    {
        byte[] correctHash = null;
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["HealthCourses"].ConnectionString))
        {
            SqlCommand cm = new SqlCommand("[dbo].[HealthCourses_GetUserPassword]", conn);
            cm.CommandType = CommandType.StoredProcedure;
            cm.Parameters.Add("@users_username", SqlDbType.VarChar, 50).Value = userName;
            conn.Open();
            correctHash = cm.ExecuteScalar() as byte[];
        }

        if (correctHash == null)
        {
            // User not found.
            return false;
        }
        else
        {
            return PasswordHash.ValidatePassword(password, correctHash);
        }
    }

    protected void btn_ProgramInfoLogIn_Click(object sender, EventArgs e)
    {
        if (IsValidPassword(txtUserName.Text, txtPassword.Text))
        {
            Session["UserNameSessionID"] = txtUserName.Text;
            FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);
        }
        else
        {
            lblLogInError.Text = "Invalid Credentials!";
        }
    }
You may need to change IsValidPassword method or introduce new method for CheckPasswordExpiry check.
Your login method may look like this:
protected void btn_ProgramInfoLogIn_Click(object sender, EventArgs e)
    {
        if (IsValidPassword(txtUserName.Text, txtPassword.Text))
        {
              if(CheckPasswordExpiry(txtUserName.Text))
             {              
                     //Password expired, do not authenticate user. just redirect to password change page
                   Response.Redirect("ChangePasswordPage.aspx");
             }
             else
             {
                      Session["UserNameSessionID"] = txtUserName.Text;
                      FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);

              }
         }
        else
        {
            lblLogInError.Text = "Invalid Credentials!";
        }
    }

private bool CheckPasswordExpiry(string userName)
{
     //Check password expiry with userName against user_password_change field in your table
    If ( passwordIsMoreThan90DaysOld)  //implement your logic to check user password is older than 90 days.
           return true;  //its expired
    else
           return false;
}

Open in new window

Hello asp_net2:
Thanks for replying. I'm a little confused of course. Is the first code snippet above that you posted for Checking the Password strenght itself only? If so, do I need to tie that in to my creation of a new user? I was planning on using regular expressions using AJAX to control the password strength but I also like your solution as well.
Yes, wherever you save the user password you must check it to be sure that it is secure enough, is simple, just use this code before you reach your DB saving method (of course replace the control names with the correct ones):
try
{
    PasswordPolicy.CheckPassword(TextBoxMyPassword.Text);
}
catch (PasswordPolicy.PasswordPolicyException ex)
{
    // Display this error to your user
    MyLabel.Text = ex.Message;
    return; //<-- Important
}

Open in new window

Dont rely only in javascript validations, that can be easily bypassed, you always must check your validations on the server side.


Also, I'm not sure if this is oky to do but I added another field in my table called "users_password_date" which is tied to SQL (getDate()) function. So if a user would change his/her password then it would change the users_password_date to the current data it was changed without user adding the date.
I'm not sure what you mean with this, but if you are talking about a default column value it only works for inserts not updates.

Also, I don't understand Frosty555's method but I do like gery128 method in post 37069710.
Frosty555 suggestion is good because will can control that an user don't use the same password twice in a sort time period. The simplest thing that you can do without that implementation is to check that the new password is not like the current one.
Avatar of Brian

ASKER

@ gery128:

Is there anyway you can show me how to compare the two dates in the CheckPasswordExpiry Event Handler. I would need to compare the current date with the data stord in the DB labeld users_password_date.

Avatar of Brian

ASKER

@yv989c,

Thank you yv989c, I understand what you are saying now. I think the only think left now is to compare the two dates, current data and date stored in DB labeled users_password_date and to if the data is older than 90 days and if it is redirect to ChangePassword page.
ASKER CERTIFIED SOLUTION
Avatar of Carlos Villegas
Carlos Villegas
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
And remember, all the users must have access to your ChangePassword.aspx page, so your web.config must have these entry:
<location path="ChangePassword.aspx">
	<system.web>
		<authorization>
			<allow users="*"/>
		</authorization>
	</system.web>
</location>

Open in new window

@asp_net2
I think, yv989c's suggested changes in SP will give you an idea about how to compare the two dates for password expiry check.
Avatar of Brian

ASKER

Is there a way to do the two date checks in code instead of SQL?
ya, certainly,

            DateTime changePasswordDate = new DateTime(2011, 09, 11); //here I am using it for just testing. you //should fetch value from database in changePasswordDate variable from filed users_password_change field
            if (changePasswordDate.AddDays(90) > DateTime.Today)
            {

            }

Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Brian

ASKER

Hi yv989c and gery128,

I'm very sorry that I have been away from this post. I got caught into trying to learn how to Encrypt / Decrypt Data in my DB (Not Hashing) and I have been beating my head on that. I'm going to close this post and award the points but before I do if either of you two can help me with another post in regards to Encrypting / Decrypting data then I would REALLY appreciate it. I'm trying to go by the books example, the book is called "Pro ASP.NET 4.0 using C# 2010" by APress and I'm able to get the data to Encrypt but not able to Decrypt. Anyway let me know if either of you two could help, below is the link to that post.

https://www.experts-exchange.com/questions/27452720/Encrypt-Decrypt-using-Rigndael-Algorithm.html
Avatar of Brian

ASKER

Thank you both very much for all your help!!!