• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 385
  • Last Modified:

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.
0
asp_net2
Asked:
asp_net2
  • 8
  • 8
  • 4
  • +2
2 Solutions
 
Frosty555Commented:
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.
0
 
gery128Commented:
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.
0
 
MuraliCommented:
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...
0
Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

 
gery128Commented:
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.
0
 
gery128Commented:
@Murali1984
This question is of asp.net web application users' password policy and not of Windows OS.
0
 
asp_net2Author Commented:
@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.
0
 
gery128Commented:
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.
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
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

0
 
asp_net2Author Commented:
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.
0
 
asp_net2Author Commented:
@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!";
        }
    }
0
 
gery128Commented:
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

0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
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.
0
 
asp_net2Author Commented:
@ 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.

0
 
asp_net2Author Commented:
@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.
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
Hello asp_net2, I think that you can do that by doing this:

1. Update your HealthCourses_GetUserPassword SP:
ALTER PROCEDURE
	[dbo].[HealthCourses_GetUserPassword]
(
	@users_username varchar(50)
)
AS

SELECT
	users_password,
	CAST(CASE WHEN DATEADD(DAY, 90, ISNULL(users_password_date, GETDATE())) < GETDATE() THEN 1 ELSE 0 END AS BIT) AS PasswordExpired
FROM
	dbo.HealthCourses_Users
WHERE
	users_username = @users_username

Open in new window


2. Update your IsValidPassword method:
private bool IsValidPassword(string userName, string password)
{
    byte[] correctHash = null;
    bool passwordExpired = false;

    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();
        using (SqlDataReader dr = cm.ExecuteReader(CommandBehavior.SingleRow))
        {
            if (dr.Read())
            {
                correctHash = dr["users_password"] as byte[];
                passwordExpired = Convert.ToBoolean(dr["PasswordExpired"]);
            }
        }
    }

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

            return true;
        }
        else
        {
            // Invalid password.
            return false;
        }
    }
}

Open in new window


3. Add this class to your App_Code folder, or in your login page, your choice:
public class PasswordExpiredException : Exception
{
    public PasswordExpiredException() { }
}

Open in new window



4. Then in your btn_ProgramInfoLogIn_Click method you must catch the PasswordExpiredException to know the user password must be changed:
protected void btn_ProgramInfoLogIn_Click(object sender, EventArgs e)
{
    try
    {
        if (IsValidPassword(txtUserName.Text, txtPassword.Text))
        {
            Session["UserNameSessionID"] = txtUserName.Text;
            FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);
        }
        else
        {
            lblLogInError.Text = "Invalid Credentials!";
        }
    }
    catch (PasswordExpiredException)
    {
        // If PasswordExpiredException is raised this will redirect the user to your Change Password page.
        Response.Redirect("ChangePassword.aspx");
    }
}

Open in new window



The previous code can contain typos, I have not tested it.
0
 
Carlos VillegasFull Stack .NET DeveloperCommented:
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

0
 
gery128Commented:
@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.
0
 
asp_net2Author Commented:
Is there a way to do the two date checks in code instead of SQL?
0
 
gery128Commented:
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

0
 
gery128Commented:
It should be like this.
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)
            {
                     //Password is older than 90 days redirect user to change password page.
            }

Open in new window

0
 
asp_net2Author Commented:
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.

http://www.experts-exchange.com/Programming/Languages/.NET/ASP.NET/Q_27452720.html
0
 
asp_net2Author Commented:
Thank you both very much for all your help!!!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

  • 8
  • 8
  • 4
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now