In a past tutorial we showed you how to use pam_cracklib to force password complexity in Red Hat 6 or CentOS 6 systems. In Red Hat 7 pam_pwquality replaced cracklib as the default pam module for password checking. The pam_pwquality module is also supported in Ubuntu and CentOS and most likely others. This module simplified the creation of password policies to ensure users are meeting your password complexity standards.
For a long time the conventional thinking for passwords has been to force the use upper & lower case letters, digits and symbols in your passwords. These basic password complexity rules were pushed heavily in the last decade. But there has been a lot of discussion as to whether or not this is a good practice. The basic argument against this is that forcing users to create such arbitrary passwords causes them to write them down or otherwise store them in an insecure manner.
Another policy that has recently been called into question is forcing users to change their passwords every x number of days. There have been some studies that show this is detrimental to good security.
There are many papers and articles written for both sides of the argument. This is not something that we will discuss here. This article is intended to demonstrate how to set password complexity, not guide you in creating a policy.
Password Policy Options
Below is a list of password policy options with a brief description of each. A lot of these are the same as were used in the cracklib module. This makes it easy to port your policies from an old system.
- difok – This is the number of characters in your new password that must NOT be present in your old password. default = 5
- minlen – Minimum length of new password. default = 9
- ucredit – Maximum number of credits for having uppercase letters ( if > 0 ), or minimum number of uppercase letters required ( if < 0 ). default = 1
- lcredit – Maximum number of credits for having lowercase letters ( if > 0 ), or minimum number of lowercase letters required ( if < 0 ). default = 1
- dcredit – Maximum number of credits for having digits ( if > 0 ), or minimum number of digits required ( if < 0 ). default = 1
- ocredit – Maximum number of credits for having other characters ( if > 0 ), or minimum number of other characters required ( if < 0 ). default = 1
- minclass – Sets the number of required classes. Classes include the above (upper case letter, lower case letter, digit, and non-alpha). default = 0
- maxrepeat – Maximum number of repeated characters allowed. default = 0
- maxclassrepeat – Maximum number of consecutive characters in the same class. default = 0
- gecoscheck – Checks if the password matches any words in the users GECOS strings (User information like real name, location,etc) default = 0 (off)
- dictpath – Path to cracklib dictionaries.
- badwords – Space separated list of words that are forbidden in passwords (Company name or department, the word “password”, etc..)
If the credits look confusing, that’s because the are. We will explain credits in depth in the next couple sections.
Configuring a Password Policy
Before you start editing your configuration files it is a good idea to have a baseline password policy written down. For our example, we will be using the following password complexity rules.
- The password must be 15 characters in length.
- The password must not repeat the same character more than two times.
- The password must not repeat any class of character four times.
- The password must contain characters from every class.
- The new password must have 5 new characters when compared to the old password.
- Enable GECOS check.
- Forbid words “password, pass, word, putorius”
Now that we have our policy laid out, we can edit the /etc/security/pwquality.conf file to enforce our new password complexity requirements. Here is an example file commented for clarity.
# Make sure 5 characters in new password are new compared to old password difok = 5 # Set the minimum length acceptable for new passwords minlen = 15 # Require at least 2 digits dcredit = -2 # Require at least 2 upper case letters ucredit = -2 # Require at least 2 lower case letters lcredit = -2 # Require at least 2 special characters (non-alphanumeric) ocredit = -2 # Require a character from every class (upper, lower, digit, other) minclass = 4 # Only allow each character to be repeated twice, avoid things like LLL maxrepeat = 2 # Only allow a class to be repeated 4 times maxclassrepeat = 4 # Check user information (Real name, etc) to ensure it is not used in password gecoscheck = 1 # Leave default dictionary path dictpath = # Forbid the following words in passwords badwords = password pass word putorius
As you may have noticed, some of the options in our file are redundant. For example, the minclass setting is redundant as we already require 2 of each class using the [u,l,d,o]credit fields. Also our badwords is redundant because we do not allow any class to repeat 4 times (all of our bad words are lowercase letters). I included these just to demonstration on how to use them for setting password policy.
Once you have created your policy, you may consider forcing users to change their passwords upon next login.
Another odd thing you may have noticed is that the [u,l,d,o]credit fields have a negative number. This is because if the number is greater than or equal to 0, it would give credit (character credit) to having those in your password. If the setting is a negative number, it means that number is required.
What are Credits?
I like to call them character credits because I think it makes their purpose more clear. If the setting is greater than zero, you get x amount of “character credits” towards the password length. For example, if all of the credit lines (u,l,d,o) were set to 1, and the password length requirement was set to 6, you would need 6 characters to meet the length requirement because each uppercase, lower case, digit and symbol would give you one credit.
If you set dcredit to equal 2, you could theoretically use a nine character password and get 2 “character credits” for the digit which would equal 10.
Here is an example, I have the password length requirement set to 13, the dcredit set to 2, and the rest set to zero (0).
$ pwscore Thisistwelve Password quality check failed: The password is shorter than 13 characters $ pwscore Th1sistwelve 18
As you can see, my first check failed because the password was less than 13 characters. The second time I changed a letter “I” to a number “1” and received 2 credits for the digit, which equaled the required 13 characters.
Testing Your Password
The libpwquality package provides the functionality outlined in this article. It also provides a program called pwscore that supplies a method to check your password complexity. You can see we used it above to test the credits.
The pwscore utility reads from stdin, simply run the utility and then type your password at it will either give you an error or a score value from 0 to 100.
The password quality score is relative to the minlen setting in the configuration file. But in general values below 50 can be treated as moderate quality and above it fairly strong quality. Any password that passes the quality checks (especially the mandatory cracklib check) should withstand dictionary attacks and scores above 50 with the default minlen setting even fast brute force attacks.
-pwscore man page
Configuring pwquality is a breeze compared to the awkwardness of using cracklib by direct editing of pam files. In this tutorial we covered everything you should need to set password policies in Red Hat 7, CentOS 7 and even Ubuntu systems. We also covered the concepts of credits, which I always felt were poorly explained for folks new to this.