Aller au contenu
apim.one

The blog

Rate limiting is not security

A quota protects your backend against your legitimate clients. It protects next to nothing against an attacker. Telling the two apart avoids a false sense of protection.

In most scoping workshops, the "protection against abuse" line of the security grid is ticked by a single feature: rate limiting. That is a misunderstanding, and a dangerous one, because it gives the feeling that the subject is handled.

What a quota really does

Rate limiting answers a capacity question: how many calls is this consumer entitled to make, so that the backend holds and the other consumers are not affected?

It is a mediation function, not a security one. It protects your platform against its own success: the misconfigured batch job of an internal team, the retry loop of a partner, the traffic spike of a client who plugged in a new channel without warning. These cases are real, frequent, and the quota is the right answer.

What a quota does not do

An attacker does not exceed quotas. He works below them.

  • Resource enumeration works very well at 10 requests per second, for hours, varying the identifiers. The quota sees nothing: every call is valid.
  • Credential stuffing spreads across thousands of IP addresses, each one far below the threshold.
  • Exfiltration through a stolen key looks, seen from the quota, like the normal traffic of the client it was stolen from.

What detects these behaviours is not a rate threshold, it is an analysis of the content and the shape of the calls: an abnormal 404 error rate over a range of identifiers, the variety of parameters, a geography inconsistent with the consumer's history. In other words, detection, not rate limiting.

The question of scope

The second misunderstanding concerns the quota key. A quota per IP address is next to useless in 2026: legitimate consumers come from behind corporate NAT and shared cloud platforms, attackers run on rented residential addresses.

The useful quota sits on the application identity: the key, the OAuth client, the certificate. Which assumes that every consumer has an identity of its own, and therefore that self service subscription works. A platform where teams pass keys around under the table can neither limit nor detect properly: it sees one single large consumer.

Every protection has its layer

The third misunderstanding is to expect everything from the gateway. The three families of protection do not sit in the same place, and confusing them amounts to paying for one and having none.

What you want to stopWhere it sitsWhy not elsewhere
Raw volume, denial of service, botsUpstream: CDN, L7 protection, web application firewallThe gateway that absorbs the flood goes down with it
A consumer going over its contractOn the gateway, by identityIt is the only point that knows the subscription
The exhaustion of an expensive resourceIn the service, per expensive requestOnly the service knows that a report costs a thousand times a read

The practical consequence is simple: a gateway quota set to stop a volumetric attack arrives too late, since the traffic has already crossed TLS termination and consumed a connection.

Set the quota for what it is: capacity

Since the quota serves capacity, it is set on legitimate traffic, never on a hunch about what an attacker would do.

The method fits in four steps. Measure, over thirty days, the peak rate per consumer, at the 99th percentile of one minute windows. Set the limit at two or three times that value: the margin absorbs a recovery after an incident without letting a loop through.

Then choose the window according to what you protect. A one-second window protects the backend from a burst, a one-day window protects a budget, and the two are set together because they do not address the same risk. Finally, fix a low default value for every new consumer, since you have no measurements for it.

Two settings then decide whether the peace holds. The waiver must be a request handled in self-service, with an expiry date, failing which it becomes a permanent exception that nobody reviews. And the refusal must be actionable by the consumer: a 429 code together with a retry delay, failing which clients retry immediately and turn the quota into a load amplifier.

What to build instead

The real protection of an exposed API plays out on four levels, and the quota is only the first:

  1. Capacity: the quota set as above. That is rate limiting, in its rightful place.
  2. Authentication: no anonymous operation on data, individual application identities, a rotation that works.
  3. Authorisation: access control per resource, the one that stops client A from reading client B's data by changing an identifier in the URL. It is the first risk of the OWASP API Security ranking, it happens at normal rate with a valid authentication, and no quota addresses it.
  4. Detection: alerts on abnormal patterns, plugged into the gateway logs, with someone who receives them.

The simple test

Take a legitimate API key from your platform and try, at 5 requests per second, to enumerate a resource that does not belong to you. If nothing stops you and nobody is alerted, your "protection against abuse" is a capacity quota, and it is better to know it before somebody else finds out.

It is one of the access tests we replay at every audit, and it is rarely conclusive the first time round.

Published in June 2025.

On the same subject