servewaf always answers rproxy well within its time limit (closes #182)
check / check (push) Successful in 8m31s
check / check (push) Successful in 8m31s
A question waits on GeoJS at most 800ms, the new default of SWWAF_LOOKUP_TIMEOUT. In enforce mode it does not wait at all when it is over the header limits, on a fetched blocklist with deny, on the CrowdSec decision list, or over a whole rate limit. Not waiting never lowers a client's limit. Just before the Core Rule Set, servewaf refuses more than 50 cookies or 100 header fields with 431. Shared default changed: SWWAF_LOOKUP_TIMEOUT also applies to smallwebwaf with no command. Judgement call: SWWAF_REPUTATION_TIMEOUT stays 2s, since no request waits on the DNS blocklists or AbuseIPDB. Model: opus-5-5
This commit was merged in pull request #183.
This commit is contained in:
@@ -1102,8 +1102,9 @@ metrics.
|
||||
|
||||
### The answer
|
||||
|
||||
`servewaf` runs steps 3 to 12 of "What happens to a request", in that order.
|
||||
Every answer but the last below carries `X-Smallwebwaf-Disposition`.
|
||||
`servewaf` runs steps 3 to 12 of "What happens to a request", in that order,
|
||||
with the header limits just before step 12 (see "Answering in time"). Every
|
||||
answer but the last below carries `X-Smallwebwaf-Disposition`.
|
||||
|
||||
- `X-Smallwebwaf-Disposition: allow`, status `200`, no body. `rproxy` passes the
|
||||
request to the app. With `SWWAF_ADD_LOOKUP_HEADERS` the answer also carries
|
||||
@@ -1114,6 +1115,7 @@ Every answer but the last below carries `X-Smallwebwaf-Disposition`.
|
||||
status is one of:
|
||||
- `SWWAF_BAN_RESPONSE`, for a refusal;
|
||||
- `403`, for a `block` rule or the Core Rule Set;
|
||||
- `431`, for a request over the header limits;
|
||||
- `404`, for a path under `/_smallwebwaf/` that passes the checks, so that
|
||||
the app never sees that prefix.
|
||||
- `X-Smallwebwaf-Disposition: close`, status `200`, no body. This takes the
|
||||
@@ -1131,6 +1133,70 @@ The Core Rule Set inspects the body a question carries only while
|
||||
does not inspect a JSON or XML body of 64 KiB or more, which may have been cut
|
||||
short.
|
||||
|
||||
### Answering in time
|
||||
|
||||
`rproxy` stops waiting for `servewaf` after `SWRP_TIMEOUT_MS`, by default 2
|
||||
seconds, and `SWRP_DEFAULT_DISPOSITION` then decides. So at the defaults,
|
||||
`servewaf` answers a request well within that time, whatever the request and
|
||||
whatever its outside sources do.
|
||||
|
||||
GeoJS is the only outside source a question can wait on. A question waits only
|
||||
when step 5 says so, and for at most `SWWAF_LOOKUP_TIMEOUT`, by default 800
|
||||
milliseconds. A client without an answer by then counts as unknown. No question
|
||||
waits on these, which run in the background:
|
||||
|
||||
- the DNS blocklists and AbuseIPDB;
|
||||
- fetching the blocklists, the CrowdSec decision list and the file
|
||||
`SWWAF_ASN_LIMIT_PERCENT_URL` names.
|
||||
|
||||
In `enforce` mode, a question does not wait for GeoJS when it is a request:
|
||||
|
||||
- over the header limits;
|
||||
- from a client on a fetched blocklist, while `SWWAF_BLOCKLIST_ACTION` is
|
||||
`deny`;
|
||||
- from a client on the CrowdSec decision list;
|
||||
- that would take its client over a rate limit at 100% of it, since a percentage
|
||||
can only lower a limit.
|
||||
|
||||
Such a request still goes through the steps in their order. Its client's AS
|
||||
number and country stay unknown until GeoJS has answered. So while
|
||||
`SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES` is set, that list can refuse it first.
|
||||
`SWWAF_UNKNOWN_LIMIT_PERCENT` does not apply to it until then, so not waiting
|
||||
never lowers its limit.
|
||||
|
||||
The static lists and bans come before the lookup, so they never wait. These can
|
||||
still wait for GeoJS:
|
||||
|
||||
- a country list, which needs the answer;
|
||||
- a rate limit a percentage has lowered, which needs the answer;
|
||||
- a DNS blocklist or AbuseIPDB, while `SWWAF_REPUTATION_ACTION` is `deny`;
|
||||
- a trap path;
|
||||
- a rule file;
|
||||
- the Core Rule Set.
|
||||
|
||||
The header limits are fixed, with no setting. `servewaf` refuses a request over
|
||||
either one:
|
||||
|
||||
- more than 50 cookies. Each part of its `Cookie` headers between semicolons
|
||||
counts as one, unless it is empty or only spaces and tabs.
|
||||
- more than 100 header fields. A header sent twice counts twice. `Host` and
|
||||
`Transfer-Encoding` do not count. `X-Request-ID` and `X-Forwarded-Proto` do.
|
||||
|
||||
Real clients never reach these limits. The answer is `deny` with `431`, and the
|
||||
log line's action is `too_large`. The refusal makes no ban and is no offence.
|
||||
The rate limits count the request as usual, so a client that keeps sending such
|
||||
requests breaks a limit.
|
||||
|
||||
The limits apply on every path and in every `SWWAF_WAF_MODE`. A client in
|
||||
`SWWAF_ALLOW_NETS` skips them, as it skips the Core Rule Set. In `observe` mode
|
||||
such a request is answered `allow` with `would_action`, and the Core Rule Set
|
||||
does not read it.
|
||||
|
||||
The Core Rule Set runs each of its rules on each cookie, so thousands of small
|
||||
cookies would keep it busy for over a second. Within the limits, one long cookie
|
||||
or query string can still keep it busy for a fraction of a second. So enough
|
||||
such requests at once can overload `servewaf` past `SWRP_TIMEOUT_MS`.
|
||||
|
||||
### The report
|
||||
|
||||
Once the visitor's answer has ended, `rproxy` sends `POST /_smallwebwaf/report`
|
||||
|
||||
Reference in New Issue
Block a user