This is the thirteenth security tip from Laravel Security in Depth.
Subscribe to receive weekly security tips and monthly In Depth emails covering Laravel Security topics.
Passwords are the digital keys that keep user accounts safe, but passwords only work when they are secret and unguessable. The classic “fix” is to impose password complexity rules, but who here hasn’t simply added a
! onto the end of the password they wanted to use? Password complexity rules and complexity indicators are superficial fixes that don’t solve the root problem: users are lazy and reuse the same passwords everywhere.
The problem with reusing passwords is simple: If user reuses the same password on multiple sites (i.e. A, B, & C) and site A is compromised and has stored passwords insecurely, the hacker now has a working
username:passwordcombination to use on site’s B & C.
These passwords are known as Compromised or “Pwned” Passwords.
To prevent users from using compromised passwords, we can use the excellent Pwned Passwords service by Troy Hunt, which aggregates passwords from data breaches and provides a secure* way to check if passwords have been pwned or not.
The Laravel Password Validation Rule comes with an
uncompromised() method, which we can use to quickly validate for pwned passwords when registering users or changing passwords:
$validator = Validator::make($request->all(), [ 'password' => [ 'required', 'confirmed', Password::min(8)->uncompromised() ], ]);
There’s always a but…
You can’t simply add the
uncompromised rule into your validator and consider the job done. When the validator fails on user registration, this is the message your users will see:
'The given :attribute has appeared in a data leak. Please choose a different :attribute.'
If your audience are all technical folks, people who know what a “data leak” is and use a password manager, then this message will probably make them laugh and they’ll pick a new password. But what if they are non-technical, or just-technical-enough, but don’t know what a “data leak” is? What if they reuse the same password everywhere because they want to remember it? There is a good chance they’ll simply go elsewhere and find one of your competitors to sign up for.
Don’t get me wrong, I’m not saying you shouldn’t use the
uncompromised() password rule, but I think you need to take it a step further. We need to encourage our users to use secure passwords, and to do so, we need to teach them what a secure password is.
If your users are technical, you can expand on the validation message to provide links to resources like Pwned Passwords and extra FAQ entries. This is something that Stefán Jökull Sigurðarson did at EveOnline very successfully:
If your users are non-technical, maybe make it soft-fail, and allow them to use a pwned password but add extra authentication steps in or provide information for them to read about passwords if they are interested (some “non-technical” users would love to learn more but just don’t know where to start!). A magic link sent via email is easy method for non-technical folks to authenticate themselves, and shifts the burden of password authentication onto their email providers – who likely have much bigger security budgets than you!
Finally, don’t forget that SMS-based Multi-Factor Authentication is not insecure**. It’s far more secure than using a password on it’s own, and it’s also incredibly accessible for non-technical users who wouldn’t know where to start with a authentication app. So don’t be afraid to implement SMS MFA as an option.
(Ok, so you should throw App-based Auth, U2F, and AuthN in there too… but if you only have time to implement one type of MFA, consider which is the most suitable for your userbase.)
* Despite all of the security advice of “Never provide your password to a third-party”, the Pwned Passwords service is safe and secure and you can use it to check passwords.
See https://www.troyhunt.com/ive-just-launched-pwned-passwords-version-2/#cloudflareprivacyandkanonymity for more information.
** SMS MFA attacks are specifically targeted against high value targets, not normal users. Plus, the “SMS MFA” insecurity is usually just a password reset which bypasses the password entirely anyway. If you’re a high value target, you should be using a secure password anyway.
Interested in learning more?
If you want to learn more about Laravel security, become a Laravel Security In Depth subscriber and receive monthly In Depth emails about Laravel Security concepts, and access our intentionally vulnerable demo site, plus weekly security tips to help you write secure code.
Past In Depth topics include: Insecure Direct Object References (IDOR), Magic Emails, Signed URLs, Policy Objects, Content Security Policies (CSPs), Timing Attacks, Rehashing Passwords, Guessing Placeholders, Escaping Output Safely (XSS), SQL Injection, and Encryption.
Subscribers can access all past emails, so you can get started right away learning the topics that interest you.