?
Solved

Password Policy's

Posted on 2011-11-01
22
Medium Priority
?
380 Views
Last Modified: 2012-05-12
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
Comment
Question by:asp_net2
  • 8
  • 8
  • 4
  • +2
22 Comments
 
LVL 31

Expert Comment

by:Frosty555
ID: 37062738
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
 
LVL 9

Expert Comment

by:gery128
ID: 37062761
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
 
LVL 10

Expert Comment

by:Murali
ID: 37062770
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
Free learning courses: Active Directory Deep Dive

Get a firm grasp on your IT environment when you learn Active Directory best practices with Veeam! Watch all, or choose any amount, of this three-part webinar series to improve your skills. From the basics to virtualization and backup, we got you covered.

 
LVL 9

Expert Comment

by:gery128
ID: 37062783
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
 
LVL 9

Expert Comment

by:gery128
ID: 37062796
@Murali1984
This question is of asp.net web application users' password policy and not of Windows OS.
0
 
LVL 4

Author Comment

by:asp_net2
ID: 37063686
@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
 
LVL 9

Expert Comment

by:gery128
ID: 37069710
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
 
LVL 17

Expert Comment

by:Carlos Villegas
ID: 37070206
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
 
LVL 4

Author Comment

by:asp_net2
ID: 37072004
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
 
LVL 4

Author Comment

by:asp_net2
ID: 37072029
@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
 
LVL 9

Expert Comment

by:gery128
ID: 37074853
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
 
LVL 17

Expert Comment

by:Carlos Villegas
ID: 37080619
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
 
LVL 4

Author Comment

by:asp_net2
ID: 37088087
@ 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
 
LVL 4

Author Comment

by:asp_net2
ID: 37088090
@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
 
LVL 17

Accepted Solution

by:
Carlos Villegas earned 1000 total points
ID: 37088171
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
 
LVL 17

Expert Comment

by:Carlos Villegas
ID: 37088179
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
 
LVL 9

Expert Comment

by:gery128
ID: 37088300
@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
 
LVL 4

Author Comment

by:asp_net2
ID: 37088313
Is there a way to do the two date checks in code instead of SQL?
0
 
LVL 9

Expert Comment

by:gery128
ID: 37088370
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
 
LVL 9

Assisted Solution

by:gery128
gery128 earned 1000 total points
ID: 37088388
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
 
LVL 4

Author Comment

by:asp_net2
ID: 37159120
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
 
LVL 4

Author Closing Comment

by:asp_net2
ID: 37160185
Thank you both very much for all your help!!!
0

Featured Post

Restore individual SQL databases with ease

Veeam Explorer for Microsoft SQL Server delivers an easy-to-use, wizard-driven interface for restoring your databases from a backup. No expert SQL background required. Web interface provides a complete view of all available SQL databases to simplify the recovery of lost database

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Simulator games are perfect for generating sample realistic data streams, especially for learning data analysis. It is even useful for demoing offerings such as Azure stream analytics, PowerBI etc.
Please read the paragraph below before following the instructions in the video — there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, …
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…
Suggested Courses
Course of the Month13 days, 14 hours left to enroll

807 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question