Leave SWWAF_RATE_LIMIT_EXEMPT_PATHS out of the request rate limits (closes #77)
check / check (push) Waiting to run
check / check (push) Waiting to run
A request is neither counted nor refused by the request rate limits when the path the app will act on starts with one of the comma-separated prefixes in SWWAF_RATE_LIMIT_EXEMPT_PATHS. That path is the request's path percent-decoded, with its . and .. segments and repeated slashes resolved, so /assets/..%2Flogin is /login and is counted. The static lists, bans and the country lists still apply. The setting is empty by default, and a prefix that does not start with / stops the start. README.md documents it. Model: opus-5-5
This commit is contained in:
@@ -13,22 +13,23 @@ JSON log line for every request.
|
||||
|
||||
Status: the first two milestones are built
|
||||
(https://git.eeqj.de/sneak/smallwebwaf/issues/13 and
|
||||
https://git.eeqj.de/sneak/smallwebwaf/issues/14), and so are six parts of
|
||||
milestone 3: the static lists, the bans that broken rate limits lead to and the
|
||||
JSON state files, which come next in the build order, `observe` mode, which
|
||||
comes a little later, and the metrics endpoint and the header size and the idle
|
||||
time as settings, which come last in it. `smallwebwaf` passes each request to
|
||||
the app and the app's answer back, unchanged, within its timeouts and size
|
||||
limits, works out each client's address, bans a client that sends too many
|
||||
requests, refuses a client that comes from a country you refuse or from a
|
||||
network you refuse, lets the networks you choose through, keeps its bans, each
|
||||
client's counters and history, and GeoJS's answers in JSON files across
|
||||
restarts, writes a JSON log line for every request, serves Prometheus metrics to
|
||||
a scraper that holds the metrics token, and in `observe` mode passes on the
|
||||
requests it would refuse, logging what it would have done with them. It comes as
|
||||
the image the app's own image is built on. The rest of the design comes after
|
||||
that, in the order of the build order in [`SPEC.md`](SPEC.md). The survey of
|
||||
existing tools that led to the design is in [`EVALUATION.md`](EVALUATION.md).
|
||||
https://git.eeqj.de/sneak/smallwebwaf/issues/14), and so are seven parts of
|
||||
milestone 3: the static lists, the bans that broken rate limits lead to, the
|
||||
JSON state files and the paths the rate limits do not count, which come next in
|
||||
the build order, `observe` mode, which comes a little later, and the metrics
|
||||
endpoint and the header size and the idle time as settings, which come last in
|
||||
it. `smallwebwaf` passes each request to the app and the app's answer back,
|
||||
unchanged, within its timeouts and size limits, works out each client's address,
|
||||
bans a client that sends too many requests, not counting those for the paths you
|
||||
choose, refuses a client that comes from a country you refuse or from a network
|
||||
you refuse, lets the networks you choose through, keeps its bans, each client's
|
||||
counters and history, and GeoJS's answers in JSON files across restarts, writes
|
||||
a JSON log line for every request, serves Prometheus metrics to a scraper that
|
||||
holds the metrics token, and in `observe` mode passes on the requests it would
|
||||
refuse, logging what it would have done with them. It comes as the image the
|
||||
app's own image is built on. The rest of the design comes after that, in the
|
||||
order of the build order in [`SPEC.md`](SPEC.md). The survey of existing tools
|
||||
that led to the design is in [`EVALUATION.md`](EVALUATION.md).
|
||||
|
||||
## Getting started
|
||||
|
||||
@@ -79,12 +80,14 @@ in `bin/state` unless `SWWAF_STATE_DIR` is set.
|
||||
- Counts each client's requests over a minute, an hour and a day. A request that
|
||||
takes the client over one of the rate limits below is refused with
|
||||
`SWWAF_BAN_RESPONSE`, `403` by default, before anything reaches the app, and
|
||||
bans the client. A client is one IPv4 address, or one IPv6 /64, since one
|
||||
abuser usually holds a whole /64. Each window is counted in two fixed buckets,
|
||||
the earlier one weighted by how much of it the window still covers. At most
|
||||
20,000 clients are kept, the least recently seen dropped first, with their
|
||||
history, and a restart gives no client a fresh allowance (see "State files"
|
||||
below).
|
||||
bans the client. A request whose path starts with one of
|
||||
`SWWAF_RATE_LIMIT_EXEMPT_PATHS` is neither counted nor refused by the rate
|
||||
limits; the static lists, bans and the country lists still apply to it. A
|
||||
client is one IPv4 address, or one IPv6 /64, since one abuser usually holds a
|
||||
whole /64. Each window is counted in two fixed buckets, the earlier one
|
||||
weighted by how much of it the window still covers. At most 20,000 clients are
|
||||
kept, the least recently seen dropped first, with their history, and a restart
|
||||
gives no client a fresh allowance (see "State files" below).
|
||||
- Bans a client that breaks a rate limit, as "Bans" in [`SPEC.md`](SPEC.md)
|
||||
describes: the first ban lasts an hour, and a limit broken again within a day
|
||||
of a ban ending bans for three times as long as that ban, so 1, 3, 9, 27 and
|
||||
@@ -191,6 +194,18 @@ it, and the effective settings are logged at start.
|
||||
requests a client may make in a minute, an hour and a day. The defaults are
|
||||
several times what one busy person produces, since a browser loading a heavy
|
||||
page makes a few hundred requests and several people often share one address.
|
||||
- `SWWAF_RATE_LIMIT_EXEMPT_PATHS` (default empty): path prefixes whose requests
|
||||
the rate limits neither count nor refuse, such as `/assets/` for static
|
||||
assets; each starts with `/`. A prefix is compared, character for character,
|
||||
with the start of the path the app will act on: the request's path, before any
|
||||
query string, percent-decoded, with its `.` and `..` segments and repeated
|
||||
slashes resolved and without a trailing slash, which is not always what the
|
||||
request log's `path` shows. `/assets/` matches `/assets/app.js`,
|
||||
`/assets//img/logo.png` and `/static/../assets/app.js`, but not `/assets/`
|
||||
itself, `/assets`, `/Assets/app.js`, `/static/assets/app.js` or
|
||||
`/assets/..%2Flogin`, which is `/login`. A prefix is written without
|
||||
percent-encoding, and there are no wildcards: `*` is a character like any
|
||||
other.
|
||||
- `SWWAF_DENIED_COUNTRIES` (default empty): countries whose clients are refused,
|
||||
for example `cn,ru,kp`.
|
||||
- `SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES` (default empty): when set, the only
|
||||
|
||||
Reference in New Issue
Block a user