Security Tip: Rate Limit Your Login Forms!
[Tip#12] It's easy to guess passwords if your app doesn't rate limit attempts...
👉 Looking to dive deeper into Laravel security? Check out Practical Laravel Security, my hands-on security course that uses interactive hacking challenges to teach you about how vulnerabilities work, so you can avoid them in your own code! 🕵️
👉 When was your last security audit or penetration test? Book in a Laravel Security Audit and Penetration Test today! 🕵️
A password is the most important thing protecting a user account. But if that password is guessable, someone could come along and figure it out, to gain access. It’s important to encourage users to use strong random passwords, but not every user will and you need to put extra protections in place to keep these users protected. One such way to that is through Rate Limiting Login Attempts.
Many apps use authentication kits, such as Laravel Breeze or Jetstream, which include rate limiting by default, but what if you need to implement your own auth flow? Or maybe your auth was set up before such kits were available? In either case, rate limiting is your responsibility. In the State of Security of Laravel Apps in 2021 report, produced by Aaron Saray at Laravel Hacker, 33% of developers were not using Rate Limiting in their apps at all, while 12% didn’t know or answer1, which suggests it’s often overlooked and underused.
If you’re using an Authentication Kit → check it includes rate limiting.
If you’re not → you need to implement your own rate limiting.
A good place to start are the Laravel Rate Limiting docs, but I’d also recommend checking out the LoginRateLimiter
in Laravel Fortify:
https://github.com/laravel/fortify/blob/1.x/src/LoginRateLimiter.php
It provides an excellent example of abstracting the rate limiter into a purpose built class, which you can easily interact with in your authentication flow.
In fact, the entire Fortify code-base is an a great reference for how to set up an authentication flow, including adding in multi-factor authentication. So if you’re working on your own authentication flow, I highly recommend you study Fortify first.
Something to think about:
Most rate limiting locks requests either by IP address or by IP and Username (as per Fortify), but it’s trivial for an attacker with a VPN or botnet to rotate IP addresses when attacking a site. You might consider rate limiting by username only, to catch these distributed attacks, or maybe a smaller IP-Username limit and a larger Username limit. The major downside is legitimate login attempts could be blocked too if there is an attack going on... That’s a balancing act you need to decide for your app and your users.
Final note: There is so much more to dig into about rate limiting that we don’t have time for today, so I have added it into my schedule for a future In Depth email!
He also theorises that “I'm not sure that all developers know that the authentication kits contain built-in rate limiting.”, so that number might not be accurate. But I know from personal experience from working in multiple companies and projects that rate limiting is incredibly easy to overlook.