Rate limiting on the wrong axis is worse than none
31 July 2026 · 5 min read
The reflex is to limit per IP. It is easy, and it is usually the wrong axis. Offices, universities and mobile carriers put thousands of real people behind one address, and an attacker can rent a thousand addresses cheaply.
Limit the thing that causes harm
Ask what the abuse actually costs. If an action sends an email to somebody, the harm is measured per recipient, so limit per recipient. If it consumes storage, limit per account. The IP is a proxy for identity and a bad one.
Two details worth getting right
- Defer rather than reject where you can. A 4xx means a real sender retries and nothing is lost.
- Do not count the attempts you rejected. If retries feed the counter, a tripped limit never recovers.
That second one is easy to get wrong and hard to notice, because it looks fine until something is actually under load.
More on for developers
Testing signup emails in CI without a real mailbox
Sleep-and-hope is why your email tests are flaky. Here is the shape that is not.
Webhook signatures, done properly
A shared secret in a header is not a signature. Here is what to send, what to check, and the two mistakes almost everyone makes on the receiving end.
Designing a signup form that does not leak who is registered
"That email is already taken" is a feature request and a privacy hole, and you usually have to pick.