Enforcing strong password criteria
You wouldn’t think that a benign-sounding topic such as strong password criteria would be so controversial, but it is. The conventional wisdom that you’ve undoubtedly heard for your entire computer career says the following:
- Make passwords of a certain minimum length.
- Make passwords that consist of a combination of uppercase letters, lowercase letters, numbers, and special characters.
- Ensure that passwords don’t contain any words that are found in the dictionary or that are based on the users’ own personal data.
- Force users to change their passwords on a regular basis.
But, using your favorite search engine, you’ll see that different experts disagree on the details of these criteria. For example, you’ll see disagreements about whether passwords should be changed every 30, 60, or 90 days, disagreements about whether all four types of characters need to be in a password, and even disagreements on what the minimum length of a password should be.
The most interesting controversy of all comes from—of all places—the guy who invented the preceding criteria to begin with. He now says that it’s all bunk and regrets having come up with it. He now says that we should be using passphrases that are long, yet easy to remember. He also says that they should be changed only if they’ve been breached.
However, having said all that, there is the reality that many organizations are still wedded to the idea of using complex passwords that regularly expire, and you’ll have to abide by their rules if you can’t convince them otherwise. And besides, if you are using traditional passwords, you do want them to be strong enough to resist any sort of password attack. So now, we’ll take a look at the mechanics of enforcing strong password criteria on a Linux system.
Installing and configuring pwquality
We’ll be using the pwquality module for the Pluggable Authentication Module (PAM). This is a newer technology that has replaced the old cracklib module. On a Red Hat 7/8 or CentOS 7/8 system, pwquality is installed by default, even if you do a minimal installation. If you cd into the /etc/pam.d directory, you can do a grep operation to see that the PAM configuration files are already set up. retry=3 means that a user will only have three tries to get the password right when logging in to the system:
[donnie@localhost pam.d]$ grep 'pwquality' * password-auth:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= password-auth-ac:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= system-auth:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= system-auth-ac:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= [donnie@localhost pam.d]$
The rest of the procedure is the same for both operating systems and consists of just editing the /etc/security/pwquality.conf file. When you open this file in your text editor, you’ll see that everything is commented out, which means that no password complexity criteria are in effect. You’ll also see that it’s very well documented because every setting has its own explanatory comment.
You can set password complexity criteria however you want just by uncommenting the appropriate lines and setting the appropriate values. Let’s take a look at just one setting:
# Minimum acceptable size for the new password (plus one if # credits are not disabled which is the default). (See pam_cracklib manual.) # Cannot be set to lower value than 6. # minlen = 8
The minimum length setting works on a credit system. This means that for every different type of character class in the password, the minimum required password length will be reduced by one character. For example, let’s set minlen to a value of 19 and try to assign Katelyn the password turkeylips:
minlen = 19 [donnie@localhost ~]$ sudo passwd katelyn Changing password for user katelyn. New password: BAD PASSWORD: The password is shorter than 18 characters Retype new password: [donnie@localhost ~]$
Because the lowercase characters in turkeylips count as credit for one type of character class, we’re only required to have 18 characters instead of 19. If we try this again with TurkeyLips, we’ll get:
[donnie@localhost ~]$ sudo passwd katelyn Changing password for user katelyn. New password: BAD PASSWORD: The password is shorter than 17 characters Retype new password: [donnie@localhost ~]$
This time, the uppercase T and uppercase L count as a second character class, so we only need to have 17 characters in the password.
Just below the minlen line, you’ll see the credit lines. Let’s say that you don’t want lowercase letters to count toward your credits. You would find this line:
# lcredit = 1
Uncomment it, and change the 1 to a 0:
lcredit = 0
Then, try assigning Katelyn turkeylips as a password:
[donnie@localhost ~]$ sudo passwd katelyn Changing password for user katelyn. New password: BAD PASSWORD: The password is shorter than 19 characters Retype new password: [donnie@localhost ~]$
This time, the pwquality really does want 19 characters. If we set a credit value to something higher than 1, we would get credit for multiple characters of the same class type up to that value.
We can also set the credit values to negative numbers in order to require a certain number of characters types in a password. For example, we could have this:
dcredit = -3
This would require at least three digits in a password. However, it’s a really bad idea to use this feature, because someone who’s doing a password attack would soon find the patterns that you require, which would help the attacker to more precisely direct the attack. If you need to require that a password has multiple character types, it would be better to use the minclass parameter:
# minclass = 3
It’s already set to a value of 3, which would require characters from three different classes. To use this value, all you have to do is to remove the comment symbol.
The rest of the parameters in pwquality.conf work pretty much the same way, and each one has a well-written comment to explain what it does.
If you use your sudo privilege to set someone else’s password, the system will complain if you create a password that doesn’t meet complexity criteria, but it will let you do it. If a normal user were to try to change his or her own password without sudo privileges, the system would not allow a password that doesn’t meet complexity criteria.
Hands-on lab for setting password complexity criteria
For this lab, you can use either the CentOS or Ubuntu virtual machine, as desired. The only difference is that you won’t perform Step 1 for CentOS:
- For Ubuntu only, install the libpam-pwquality package:
$ sudo apt install libpam-pwquality
- Open the /etc/security/pwquality.conf file in your preferred text editor. Remove the comment symbol from in front of the minlen line and change the value to 19. It should now look like this:
minlen = 19
Save the file and exit the editor.
- Create a user account for Goldie and attempt to assign her the passwords turkeylips, TurkeyLips, and Turkey93Lips. Note the change in each warning message.
- In the pwquality.conf file, comment out the minlen line. Uncomment the minclass line and the maxclassrepeat line. Change the maxclassrepeat value to 5. The lines should now look like this:
minclass = 3 maxclassrepeat = 5
Save the file and exit the text editor.
- Try assigning various passwords that don’t meet the complexity criteria that you’ve set to Goldie’s account and view the results.
In the /etc/login.defs file on your CentOS machine, you’ll see the line PASS_MIN_LEN 5.
Supposedly, this is to set the minimum password length, but in reality, pwquality overrides it. So, you could set this value to anything at all, and it would have no effect.
Setting and enforcing password and account expiration
Something you never want is to have unused user accounts remain active. There have been incidents where an administrator set up user accounts for temporary usage, such as for a conference, and then just forgot about them after the accounts were no longer needed.
Another example would be if your company were to hire contract workers whose contract expires on a specific date. Allowing those accounts to remain active and accessible after the temporary employees leave the company would be a huge security problem. In cases like these, you want a way to ensure that temporary user accounts aren’t forgotten about when they’re no longer needed. If your employer subscribes to the conventional wisdom that users should change their passwords on a regular basis, then you’ll also want to ensure that it gets done.
Password expiration data and account expiration data are two different things. They can be set either separately or together. When someone’s password expires, he or she can change it, and everything will be all good. If somebody’s account expires, only someone with the proper admin privileges can unlock it.
To get started, take a look at the expiry data for your own account. Note that you won’t need sudo privileges to look at your own data, but you will still need to specify your own username:
donnie@packt:~$ chage -l donnie [sudo] password for donnie: Last password change : Oct 03, 2017 Password expires : never Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7 donnie@packt:~$
You can see here that no expiration data has been set. Everything here is set according to the out-of-the-box system default values. Other than the obvious items, here’s a breakdown of what you see:
- Password inactive: If this were set to a positive number, I would have that many days to change an expired password before the system would lock out my account.
- Minimum number of days between password change: Because this is set to 0, I can change my password as often as I like. If it were set to a positive number, I would have to wait that number of days after changing my password before I could change it again.
- Maximum number of days between password change: This is set to the default value of 99999, meaning that my password will never expire.
Number of days of warning before password expires: The default value is 7, but that’s rather meaningless when the password is set to never expire.
With the chage utility, you can either set password and account expiration data for other users or use the -l option to view expiration data. Any unprivileged user can use chage -l without sudo to view his or her own data. To either set data or view someone else’s data, you need sudo. We’ll take a closer look at chage a bit later.
Before we look at how to change expiration data, let’s first look at where the default settings are stored. We’ll first look at the /etc/login.defs file. The three relevant lines are as follows:
PASS_MAX_DAYS 99999 PASS_MIN_DAYS 0 PASS_WARN_AGE 7
You can edit these values to fit your organization’s needs. For example, changing PASS_MAX_DAYS to a value of 30 would cause all new user passwords from that point on to have a 30-day expiration data. (By the way, setting the default password expiry data in login.defs works for both Red Hat or CentOS and Debian/Ubuntu.)