Security Tip: Rate Limit Your Login Forms!

[Tip#12] It's easy to guess passwords if your app doesn't rate limit attempts...

Security Tip: Rate Limit Your Login Forms!

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, 33% of developers were not using Rate Limiting in their apps at all, while 12% didn’t know or answer, which suggests it’s often overlooked and underused.

Therefore...

  1. If you’re using an Authentication Kit → check it includes rate limiting.
  2. If you’re not using an Authentication Kit → 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.

Found this security tip helpful? Don't forget to subscribe to receive new Security Tips each week, and upgrade to a premium subscription to receive monthly In Depth articles, or toss a coin in the tip jar.

Reach out if you're looking for a Laravel Security Audit and Penetration Test or a budget-friendly Security Review, and find me on the various socials through Pinkary. Finally, don't forget to check out Practical Laravel Security, my interactive security course.