Default request limits per minute, hour and day, sized for API use (closes #176)
check / check (push) Failing after 17m45s

The default request limits now suit programmatic use of an API, such
as an automation fleet on another host, and still catch abusive bots:

- per minute: 500, room for a fleet's busiest minute and a few first
  visits with an empty cache, and passed within seconds by a client
  firing as fast as it can;
- per hour: 20000, passed by a client that keeps up 6 a second;
- per day: 300000, passed by a scraper that keeps up 4 a second.

The byte limits and ban lengths are unchanged. SPEC.md, README.md and
docs/settings.md give the reasons; docs/gitea.md redoes the Actions
runner sums.

Judgement call: the docs/alerts.md ban example shows the minute limit.

Model: opus-5-5
This commit was merged in pull request #179.
This commit is contained in:
2026-11-04 23:02:39 +01:00
parent fdabf4974b
commit 718a2c94b2
8 changed files with 90 additions and 51 deletions
+33 -17
View File
@@ -369,22 +369,38 @@ Conventions:
owner's own networks. `SWWAF_RATE_LIMIT_EXEMPT_NETS` bypasses the request and
byte limits only; the error burst, attack detection and bans still apply.
- Many people can share one address, as in an office, on a mobile carrier or
through Tor. They are one client, and share its limits and its bans. The
default limits are sized for about 40 busy people on one address. A known
shared address busier than that belongs in `SWWAF_ALLOW_NETS` or
through Tor. They are one client, and share its limits and its bans. A known
shared address busier than the limits allow belongs in `SWWAF_ALLOW_NETS` or
`SWWAF_RATE_LIMIT_EXEMPT_NETS`.
### Request rate limits, per client
Breaking one bans the client, so the defaults sit about twice above what 40
people busy with heavy web apps make together on one address. Each such person
makes about 75 requests in a busy minute, and 1,250 an hour for ten hours a day.
Breaking one bans the client. The defaults suit programmatic use of an API, such
as an automation fleet on another host, and still stop abusive bots. A fleet of
20 agents, each making a request every 10 seconds at its busiest, makes 120
requests a minute and 7,200 an hour. Working around the clock, it makes 172,800
a day. It stays under all three limits.
A client slower than those 40 people cannot be told from them by counting. Only
the other checks can catch an abuser that slow. They include the trap paths, the
rule files, the Core Rule Set and the blocklists. An abuser that trips none of
them is not caught. A machine that talks to the app all day can still pass the
day limit. Its address belongs in `SWWAF_RATE_LIMIT_EXEMPT_NETS`.
- Per minute: 500, about 8 requests a second. It leaves room for the fleet's 120
a minute and a few quick first visits with an empty cache. A gitea page opened
with an empty cache loads about 40 files. A client firing requests as fast as
it can passes the limit within seconds.
- Per hour: 20,000, about 5.5 requests a second for a whole hour. A client that
keeps up 6 a second makes 21,600 in an hour, and passes it, at 360 a minute,
under the minute limit. The fleet's 7,200 an hour is about a third of it.
- Per day: 300,000, about 3.5 requests a second around the clock. A scraper that
keeps up 4 a second makes 345,600 a day, and passes it. At 240 a minute and
14,400 an hour, it stays under the other two limits.
Counting cannot catch a client that stays under all three limits, such as one
that keeps up 3 requests a second. Only the other checks can catch an abuser
that slow. They include the trap paths, the rule files, the Core Rule Set and
the blocklists. An abuser that trips none of them is not caught. A machine that
keeps up more than 500 requests a minute passes the minute limit. One that keeps
up more than about 5.5 a second for an hour passes the hour limit. One that
keeps up more than about 3.5 a second all day passes the day limit, as two busy
Actions runners on one address do. Such a machine's address belongs in
`SWWAF_RATE_LIMIT_EXEMPT_NETS`.
`SWWAF_RATE_LIMIT_EXEMPT_PATHS` takes path prefixes out of the count, such as
static assets or health checks; their bytes are not counted either. A prefix is
@@ -397,12 +413,12 @@ matched the same way.
### Byte limits, per client
Each of the same 40 people moves about 256 MiB an hour, for ten hours a day. The
hour and day limits sit about twice above what they move together. A response's
bytes are counted when it ends (see step 15). So the minute limit holds two of
the largest responses, with their requests, ending in the same minute. No single
download then breaks a limit. An operator who raises `SWWAF_RESPONSE_MAX_BYTES`
raises the byte limits with it.
The hour and day limits sit about twice above what 40 people busy with heavy web
apps move together on one address. Each moves about 256 MiB an hour, for ten
hours a day. A response's bytes are counted when it ends (see step 15). So the
minute limit holds two of the largest responses, with their requests, ending in
the same minute. No single download then breaks a limit. An operator who raises
`SWWAF_RESPONSE_MAX_BYTES` raises the byte limits with it.
### Size and time limits