Security Tip: Default Password Rules
[Tip#11] Why duplicate password validation rules when you can define defaults?
Greetings everyone! We’ve made it to the end of 2021, which has been a massive year for probably everyone, and for me personally it has been both incredibly rewarding and overwhelmingly difficult. I hope you and your families have had a great Christmas (if you celebrate it), and the holiday/new year period gives you some time to relax and unwind a bit. Thank you all so much for your support of Laravel Security in Depth this year, and I am very excited to see where it goes in 2022! ❤️
For the last security tip of the year, I had planned to write about rehashing passwords in Laravel, but I ended up going down a massive rabbit hole. So I bumped rehashing passwords into the next In Depth, and decided to talk about pwned passwords instead, and then proceeded to go down another rabbit hole… So for attempt number three, following the password theme, we’re going to look at Default Password Rules! It’s a feature I am constantly forgetting about, and even know I’m sure I’ve read about it in the docs before, I’m always surprised and excited to find it and wonder if it’s new. 🤣
Default Password Rules
Password Rules are one of those things that gets defined on a project or company level and then reused across an app. You’ll probably find yourself copy-pasting the rules from one validator to another when building registration, password change, etc, and then if the rules ever change
, you’ll have to bounce between all of the validators to update the rules. It doesn’t sound that hard, but it still takes effort, and if your app has multiple logins or registration forms, you’ll need to update and all of them. Luckily for us, Laravel makes this easy!Laravel’s Password Validator Rule includes the concept of Default Password Rules. You use it by defining your password rules once, usually in a Service Provider, and then you can simply refer to these rules in each validator as Password::defaults()
.
Let’s define a basic minimum length and mixed-case rule:
use Illuminate\Validation\Rules\Password;
class AppServiceProvider extends ServiceProvider
{
// ...
public function boot()
{
Password::defaults(fn () => Password::min(8)->mixedCase());
}
}
The validator can then look like this:
'password' => ['required', Password::defaults()],
Now we can change our password rules, and the validator won’t change at all.
Maybe we want to block pwned passwords in production
, as per the Laravel documentation:use Illuminate\Validation\Rules\Password;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Password::defaults(function () {
$rule = Password::min(8);
return $this->app->isProduction()
? $rule->mixedCase()->uncompromised()
: $rule;
});
}
}
That’s it. 👋
Most likely triggered by some external security audit, or compliance checklist.
I feel like this is becoming a bit of a motto for us!
I’ll dive into this in detail in a future email, but just quickly: I do not recommend validating pwned passwords without also spending time on user education, especially with a non-technical user base. You need to help your users pick better passwords, not simply block bad ones and hope they figure it out themselves.