Security Tip: Multiple Rate Limits

[Tip#32] For times when one rate limit just won't do!

Security Tip: Multiple Rate Limits

I’m always talking about avoiding using IP address in your rate limiter, since it’s so easily changed through botnets, VPNs, and good old fashioned spoofing. Instead, I recommend you use something else like a username or email address. However, using only username/email makes it really easy to denial-of-service someone out of their account.

When it comes to a simple rate limiter, you want to rate limit on both IP address and username/email, while keeping them independent of each other to prevent one from being easily rotated to bypass the limiter.

As we would expect, Laravel has the goods with it’s Multiple Rate Limits feature:

RateLimiter::for('login', function (Request $request) {
    return [
        Limit::perMinute(500),
        Limit::perMinute(5)->by($request->ip()),
        Limit::perMinute(5)->by($request->input('email')),
    ];
});

By passing an array of limits into the RateLimiter, we can define different rate limit rules, all of which need to pass for access to be granted.

This allows you to:

  1. Lock down the route in unusually high traffic (potentially indicative of a credential stuffing attack across IPs and accounts).
  2. Block single IPs smashing your endpoint.
  3. Block brute-force attempts on a single account across multiple IPs.

Super simple, and provides a lot more defensive power than a single rate limited tied to both IP and username/email.


If you've made it this far, please share this Security Tip and Securing Laravel with your Laravel friends, colleagues, and enemies! The more folks we have learning about security, the more secure code will be written, and the safer the whole community and our users will be. Also, if you tag me I'll give it a retweet, and you can find all my socials on Pinkary.