End-users = use password managers to generate unique passwords for each application
Developers = enforce password complexity policy using at least three of the four below, given a minimum length of 12 characters:
- 1 or more lowercase letters (A-Z)
- 1 or more uppercase letters (a-z)
- 1 or more number (0-9)
- 1 or more special character
AND enforce a check against the top 500 worst passwords (the more you check, the better).
This blog aims to address the issue of weak password complexity policies for web applications and provide some recommendations for developers so that you can reduce the likelihood of a user selecting weak, easily guessed passwords.
Although you could take parts of the recommendations and use it to support your password policy for a network or domain, you should be aware that there may be other features available to networks/domains that aren’t feasible for applications.
If you’re not particularly interested in reading about the problems about password policies but just want the recommendations, then jump on down to our recommendations.
So, let’s just start with the basics. We need good passwords to prevent unauthorised users from accessing sensitive parts of an application. This could be something like your social media login or your profile on a banking application.
Current Password Policies
Well, what is the problem with password policies nowadays? We see everywhere is enforcing password complexity policies where they’re asking for things like the following:
1 or more lowercase letters (A-Z) 1 or more uppercase letters (a-z) 1 or more number (0-9) 1 or more special character Minimum number of 8 characters
Figure 1. Classical current password policies
The problem is that the above criteria let you use passwords like these:
- [email protected]
If you’re thinking that these passwords are never actually used, then let us say that these are all passwords that our consultants have seen in the wild on engagements, in use on production applications.
You’re Just Not Random Enough
These classical approaches to password complexity mean that we end up with passwords that are a pain to remember for human beings, but are easily guessable for machines.
Take for example, the classic XKCD 936, which shows how using longer passwords is a much better way to reduce the success of automated password-guessing attacks.
As developers and security consultants, we want to be encouraging users to use longer passwords that provide greater entropy (randomness).
Death of the Password
It’s an old call back that I’m sure you’ve heard before, but Bill Gates predicted the death of the password in 2004, as shown in CNET’s article. In this article he talks about how traditional passwords will fail to keep up with the challenge of securing systems against attackers and to address this, Microsoft would be focusing on implementing biometrics as a form of authentication instead of traditional 2FA.
Whilst that does seem to be the trend for a lot systems (see mobile phones using biometrics for authentication such as Apple’s FaceID, or Google’s Face Unlock or the older fingerprint scanners), web application’s do not have the luxury of enforcing biometrics. This is because application’s can be used on laptops, phones, or any other smart devices and these devices may not necessarily have the capabilities to handle biometric data.
There has been tons of research into the public breaches and leaks of application passwords used by users. For example, a recent analysis by “Flame of Ignis” on public data breaches looks into nearly public breaches with 1 billion credentials (though this does get filtered down because of duplicates or just corrupt data in breaches) and saw the following trends:
- Most common password is 123456. It covers roughly 0.722% of all the passwords. (Around 7,000,000 times per 1,000,000,000).
- Most common 1000 passwords cover 6.607% of all the passwords.
- With most common 1 million passwords, hit-rate is at 36.28%, and with most common 10 million passwords hit rate is at 54.00%.
- Average password length is 9.4822 characters.
- 12.04% of passwords contain special characters.
- 37% of passwords are numbers only.
- 41% of all passwords end with digits, but only 4.522% of all passwords start with digits.
From this, we can tell that there’s still plenty of work to done for developers in enforcing good password complexity policies (even using the policies shown in Figure 1).
Our consultants have seen this similar behaviour on engagements as well where people are still using extremely weak passwords and are still getting caught using the most common passwords.
How Do Attackers Get Passwords?
If you’re wondering “how are these passwords being discovered?” then we’ll briefly touch on some types of techniques used by attackers to get access to a user’s password (but not limited to these):
- Password leaked from data breaches are used by attackers to generate “password dictionaries” for automated password-guessing attacks.
- Social engineering where an attacker tricks the user into revealing their password, this could include attacks such as email phishing attacks or through phone “vishing” attacks.
- Passwords are often stored insecurely in files on shared network drives or even sticky notes.
- Simple brute-force attacks where an attacker enumerates through all potential password variations for an account – though this is limited to systems that do not implement any account lockout/timeout protections.
- Manual password guessing based on information about a user, for example personal information such as pet names or home addresses or car registrations.
Recommendations to End-Users
In the most ideal circumstances, we (as security consultants, developers and just general security-minded individuals) should be encouraging users to use password managers to, well, manage their passwords.
Most password managers can create bespoke, complex, and secure passwords for each application reducing the impact of any future breaches that result in password leaks. There are plenty of password managers out there, we’ve selected a few for you to consider (but please do your own research to see if it’s suitable for you):
- KeePass is an offline open-sourced password manager that works for Windows, Linux and MacOS. However, there isn’t an accompanying application for mobile phones.
- BitWarden is an online open-sourced password manager that works for most operating systems including mobile OS’s and provides a web-portal. There is a self-hosted version but there is an online version run by BitWarden Inc.
- LastPass is an online password manager that similarly works for most operating systems and provides a web-portal.
Most password managers also allow you to carry out security checks against known breaches so that you know if your passwords have been compromised.
As for developers, our recommendations includes additions to the password policy recommendations provided in Figure 1. As well as requiring, a server-side check against lists of commonly used passwords such as the GitHub 500 Worst Passwords or SecList’s top 10,000 Worst Passwords.
Classical Password Complexity Policy
What’s important is to make sure that there are both in-browser and server-side controls for password strength. Using an in-browser control can reduce the number of submissions to the server, but it cannot be relied on since all client-side controls can be bypassed.
Ultimate control for password strength must lie with the server-side checks. These controls should assess the user’s password against the following guidelines and enforce at least three of the four criteria given a minimum password length greater than 12:
- 1 or more lowercase letters (A-Z)
- 1 or more uppercase letters (a-z)
- 1 or more number (0-9)
- 1 or more special character
This recommendation (as discussed above), is the classical approach to password complexity policies. Whilst it’s generally sufficient for providing a baseline security model, users often try weasel their way around password requirements. For example, a user willing to use the root word “password” would augment it to something like “Password123!” (without the quotes). This is objectively still weak despite matching strict complexity rules.
To guard against this, passwords should be checked against common password lists such as such as the GitHub: 500 Worst Passwords or SecList’s top 10,000 Worst Passwords on the server-side. These lists of common passwords have been generated by cataloguing passwords generated by humans from various database breaches.
If your application allows users to select their own username (instead of using email addresses), then you should make sure that the list of blocked passwords includes variations of the usernames. For example, this would prevent the user “Avenger” selecting the password “Avenger1234!”. The reason for this specific check is because users often select passwords related to their username.
Alternatively, consider using a third-party such as HaveIBeenPwned have provided APIs that allow developers to check if a user’s password has been compromised in a previous data breach. By utilising these APIs, you can stop users from using weak, compromised passwords.
For accounts that are considered especially sensitive (such as the administrator), consider the following:
- Implementing multi-factor authentication
- Increasing the password’s minimum length greater than 16
Additional Security Mechanisms
The following recommendations stray a bit from “Password Complexity Policies” but can be used to help limit automated password-guessing attacks by bots.
We want to limit the rate at which users can send completed login forms to bots. This can be done with one of the following methods:
- Implementing reCAPTCHA to analyse the behaviour of user’s to determine if they are a bot or not. This helps reduce automated actions from these bots.
- Rate-limiting important form actions such as login forms to reduce the effectiveness of automated password-guessing attacks.
- Implement monitoring on the login form to alert whenever numerous failed login attempts are made against accounts. These may simply be a message on the user’s dashboard to inform them of the last failed and successful login.
Although individuals methods may not provide the 100% protection that you want (as there are ways around each one), by combining multiple methods we can reduce the effectiveness of these bots.
One additional method to consider is to implement an account timeout mechanism. This works on the idea that following some set number of failed logins (for example, 5 failed logins), the account is temporarily locked out for 1 minute. Again, the idea of this mechanism is to make it more difficult for automated password-guessing bots. However, you have to consider the fact that this mechanism can be abused to cause denial-of-service to legitimate users by bots sending login attempts for all your users on your application.
The Login Form Itself
In addition to the requirements, it is important to ensure that the password field does not:
Restrict the maximum length of password: Doing so hinders users who would select more robust passwords. It is common for security conscious users who encounter a maximum length check to voice concerns publicly resulting in minor reputational damage. It may be an indicator that the password storage in the database is insecure since appropriately hashed passwords would have a fixed storage length regardless of the source password.
Restrict the use of copy and pasting passwords from password-managers: Password managers are also increasingly used by security conscious users and failing to enable their use is an inconvenience which is also often voiced publicly. Most password managers randomly generate each password before pasting it in when required. By removing the element of human choice, the complexity is more robust against brute-force.
One Final Thing
All of these recommendations are based on current research and the things that we’ve all seen in the wild. They’re written in the hopes that more application’s out there start using more secure password complexity policies.
However, you can absolutely go nuts on the level of security that you implement on an application. For example:
- You could enforce IP restriction to only allow logins from trusted IPs (useful for internal applications).
- Restrict access to applications for users with client-certificates only.
- Individual login URLs for users to make it more difficult for bots to carry out automated password-guessing efficiently.
But for the majority of Internet-facing applications, these recommendations are excessive and just cause user’s more headaches than they’re worth. Consider your user-base and apply the recommendations as seems appropriate.