servewaf always answers rproxy well within its time limit (closes #182)
check / check (push) Successful in 6m23s
check / check (push) Successful in 6m23s
A question waits on GeoJS at most 800ms, the new default of SWWAF_LOOKUP_TIMEOUT. It does not wait at all when the checks will refuse it whatever GeoJS answers. 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 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,66 @@ 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.
|
||||
|
||||
A question does not wait for GeoJS when the checks will refuse it whatever GeoJS
|
||||
answers. That 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.
|
||||
|
||||
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`.
|
||||
|
||||
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.
|
||||
- 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