1 Commits
Author SHA1 Message Date
sneak 1f71568d02 Default request limits per hour and per day, sized for API use (closes #176)
check / check (push) Successful in 6m13s
The default request limits now suit programmatic use of an API, such
as an automation fleet on another host, and still catch crawlers:

- per minute: off;
- per hour: 30000, passed by a crawler that keeps up 10 a second;
- per day: 300000, passed by one 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 and what counting cannot catch;
docs/gitea.md redoes the Actions runner sums.

Judgement call: the ban alert example in docs/alerts.md now shows the
hour limit, since the minute limit is off by default.

Model: opus-5-5
2026-11-04 19:18:40 +00:00
3 changed files with 12 additions and 14 deletions

No files matched your search

+5 -5
View File
@@ -21,11 +21,11 @@ reference documents under [`docs/`](docs/) are listed under "Documents" below.
That leaves room for programmatic use of an API, such as an automation fleet
on another host. The hour limit catches a crawler that keeps up 10 requests a
second. The day limit catches one that keeps up 4 a second around the clock.
Counting cannot catch a client slower than about 3.5 requests a second; only
the protections below can. Byte limits give each client 4 GiB a minute, 20 GiB
an hour and 200 GiB a day. A client over a limit is refused and banned. The
first ban lasts an hour. Each repeat within a day makes the next ban three
times as long. A ban that would last more than seven days is permanent.
Counting cannot catch a slower client; only the protections below can. Byte
limits give each client 4 GiB a minute, 20 GiB an hour and 200 GiB a day. A
client over a limit is refused and banned. The first ban lasts an hour. Each
repeat within a day makes the next ban three times as long. A ban that would
last more than seven days is permanent.
- Scanners that probe for secrets, such as `/.env` or `/.git/config`. The
default rule file bans such a client for seven days at its first probe. Its
next request during the ban makes the ban permanent. The default rule file
+4 -6
View File
@@ -15,9 +15,8 @@ to them.
all. Every setting has a default chosen for a service facing the internet
in 2026. A setting that needs an alert destination, an account key or a token
stays off until the operator supplies it.
- It limits each client's requests per hour and day, and its bytes per minute,
hour and day. It bounds the size and duration of every request and answer. It
detects attacks.
- It limits each client's requests and bytes per minute, hour and day. It bounds
the size and duration of every request and answer. It detects attacks.
- It bans abusers: briefly at first, for seven days on a clear sign of attack,
and permanently when they keep at it.
- It looks up each client's AS number and country. It can refuse whole countries
@@ -393,9 +392,8 @@ under the limits.
Counting cannot catch a client slower than these limits. 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 about 3.5 requests a second all day
passes the day limit, as two busy Actions runners on one address do. Its address
belongs in `SWWAF_RATE_LIMIT_EXEMPT_NETS`.
caught. A busier machine that talks to the app all day can still pass the day
limit. Its 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
+3 -3
View File
@@ -35,7 +35,7 @@ on one line:
```json
{
"instance": "fsn1app1/gitea",
"time": "2026-10-06T12:50:00.123461Z",
"time": "2026-10-06T12:00:00.123461Z",
"event": "ban",
"client": "203.0.113.9",
"netblock": "203.0.113.9/32",
@@ -44,7 +44,7 @@ on one line:
"country": "",
"reason": "requests per hour over the limit of 30000",
"detail": {
"ban_expires": "2026-10-06T13:50:00.123Z",
"ban_expires": "2026-10-06T13:00:00.123Z",
"cause": "limit",
"notes": {
"asn": "",
@@ -55,7 +55,7 @@ on one line:
"window": "hour",
"count": 30001,
"request": {
"time": "2026-10-06T12:50:00.123456789Z",
"time": "2026-10-06T12:00:00.123456789Z",
"method": "GET",
"host": "app.example",
"path": "/owner/repo/commits/branch/main?page=812",