Discover more from Securing Laravel
Security Tip: Don't Forget Rate Limiting
[Tip#43] It's essential for limiting bot attacks, and don't forget it on other sensitive routes like authentication...
Greetings friends! This week we’re covering #8 in my Top 10 security issues I’ve found during audits: Insufficient Rate Limiting. I’ve covered different aspects of it before, so today I wanted to provide a broad overview about why it’s important and link you through to my past articles to learn more on specific topics you’re interested in.
🛡️ I can help you find and fix vulnerabilities in your code! Book a security audit now! 🕵️
Looking to learn more?
⏩ Security Tip #28: Composer Audit
▶️ In Depth #11: Insecure Direct Object References (IDOR
Please consider becoming a paid subscriber to support Laravel Security in Depth.
You’ll receive weekly security tips and monthly In Depth articles, covering every aspect of building secure applications in Laravel.
Don't Forget Rate Limiting
Rate limiting is essential for web apps because it helps prevent abusive behaviour by limiting the number of requests that can be made to a server in a specific period of time.
Rate limiting helps against:
Preventing or slowing down brute-force & credential stuffing attacks by making repeated attempts too slow to try in bulk. Individual and targeted requests can still go through, but these attacks often rely on making a significant number of requests to identify working accounts and passwords.
Slowing down Denial-Of-Service (DoS) attacks by limiting the number of requests that can trigger slow operations which use up resources and slow down the targeted site.
Prevent user enumeration by (you guessed it!) slowing down the number of requests so an attacker cannot check if a large list of email addresses is present on the site.
Prevent unexpected abuse of an API endpoint, which could lead to data being scraped or system resources being used up by a single user.
Prevents guessing random tokens, which is especially important if you’re using time limited codes with a significant window and low entropy. (I’ll explain this one below!)
So yeah, you could say it’s helpful. 😉
I recommend running rate limiting on all authentication routes, anything with a guessable random token, and API routes. You could also expand it to cover any sensitive routes or routes that provide data that is at risk of being scraped. As long as you set sensible limits, it won’t affect your users, but will protect you from various attacks.
In the past, we’ve talked about:
Using Transliteration to bypass Rate Limiting (This is a fun one!)
Guessing Random Tokens?
My favourite example of why rate limiting is important comes from a site I was auditing. I discovered the SMS-based One-Time-Password (OTP) was being verified on a route without rate limiting, and the token expired in 10 minutes from being sent.
The tokens sent via SMS were a six digit number, which means possible combinations are from
999999. That’s only 1,000,000 combinations, and if we divide that by 10 minutes and 60 seconds…
We just need to send 1,667 request per second to try every combination!
This may sound like a large number of requests for your app to handle per second, but consider that half the tokens generated will be in the first half of that number (
500000), so we only need 834 per second for a 50% success rate! Plus, if you can re-request tokens to be sent when old ones expire, you could knock that requests per second speed down quite significantly over the course of an hour or so.
Throw in some simple rate limiting, and trying to guess a combination with a limitation of 5 requests per second becomes 138 days!
Credential stuffing attacks are a specific type of attack where an attacker uses a list of known usernames and passwords from breached sites, and attempts to identify and login to accounts on on other apps with the same credentials. It is a highly effective attack because most users will reuse their passwords across multiple sites, so obtaining a working password from Site A will often work on Site B.
Here’s my maths: