Security Tip: Multiple Rate Limits

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

Security Tip: Multiple Rate Limits

Greetings friends! Last week’s Canary Tokens tip was definitely a favourite, so if you missed it, definitely go back and check it out. This week I’ve got a useful little rate limiter feature to share, which one of my clients recently showed me.

Practical Laravel Security update: the XSS module has launched for the presales users, and includes 6 interactive XSS challenges. More modules will be coming soon, next up are Escaping Output and HTML & Markdown. Early Access will launch early January. You can find all the details here, or buy the presale and get started on the XSS module.

💡 Thinking about a Laravel Security Audit and Penetration Test? I’ve got some availability in May! 🕵️

Looking to learn more?
Security Tip #14: Subresource Integrity
▶️ In Depth #5: Rehashing Passwords

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 account1.

When it comes to a simple rate limiter2, 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.


  1. i.e. Maxing out the rate limit on their username/email, so legitimate login attempts hit the rate limiter too.

  2. We’ll cover a much more advanced rate limiting design in a future In Depth.