waf: decide every visitor request within rproxy's timeout (closes #394)
check / check (push) Failing after 2m58s

The Core Rule Set is the one check whose time a visitor can stretch.
At paranoia level 4 it took over 2 s on a request with an 8 KiB
request line, three 8 KiB Cookie lines and a 64 KiB form body.
SWW_WAF_CORE_RULE_SET_BODY_INSPECTION_SIZE now takes at most 8K, which
brings that request under 1 s.

A test per kind of input times the Core Rule Set on the worst request
within the limits, at the slowest settings. SPEC.md lists the limits
that bound it.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-15 17:09:00 +00:00
1 parent 23788920f7
commit 8c236369f0
9 files changed
+402 -63

No files matched your search

+22 -16
View File
@@ -704,13 +704,13 @@ files, the limits and the bans still apply to the client that sends it.
rules is loaded yet.
- `SWW_WAF_CORE_RULE_SET_BODY_INSPECTION_SIZE` switches body inspection on, up
to that size. It takes at most `64K`, since `waf` gets no more of a body than
that (see "The answer"). Form data and multipart bodies are read up to the
size. JSON and XML bodies are read only when no larger than the size, since
those cannot be read in part. Any other body is not read: the Core Rule Set
would read it as form data, where binary content such as a git push trips
rules written for text. A body the Core Rule Set cannot parse adds 5 to the
score, and so does a multipart body cut by the limit in the middle of a part's
to that size. It takes at most `8K`, so that `waf` answers in time (see
"Answering in time"). Form data and multipart bodies are read up to the size.
JSON and XML bodies are read only when no larger than the size, since those
cannot be read in part. Any other body is not read: the Core Rule Set would
read it as form data, where binary content such as a git push trips rules
written for text. A body the Core Rule Set cannot parse adds 5 to the score,
and so does a multipart body cut by the limit in the middle of a part's
header. Body inspection suits apps whose forms carry no code.
- `SWW_WAF_TRAP_PATHS` names paths the app never serves and only scanners ask
for, such as `/wp-login.php` in front of an app that is not WordPress. This is
@@ -2397,9 +2397,7 @@ In `observe` mode a request that `enforce` mode would refuse is answered
answered `404`.
The Core Rule Set inspects the body a question carries only while
`SWW_WAF_CORE_RULE_SET_BODY_INSPECTION_SIZE` is set. It inspects at most 64 KiB
less one byte. So it does not inspect a JSON or XML body of 64 KiB or more,
which may have been cut short.
`SWW_WAF_CORE_RULE_SET_BODY_INSPECTION_SIZE` is set, and at most 8 KiB of it.
### Answering in time
@@ -2474,12 +2472,20 @@ client in `SWW_WAF_ALLOW_NETS` skips them, as it skips the Core Rule Set. In
`observe` mode such a request is answered `allow` with `would_action`, and no
other check runs on 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. One 30 KB cookie or query string
would keep it busy for a third of a second or more. A request with several long
`Cookie` lines, each within the limits, can keep it as busy. Enough such
requests at once can still overload `waf` past
`SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS`.
The Core Rule Set is the one check a visitor can keep busy for long. It runs
each of its rules on each part of a request, so thousands of small cookies would
keep it busy for over a second. These fixed limits bound what it reads:
- the header limits above;
- 32 KiB for the request line and headers together, which `rproxy` refuses past
(see "`rproxy`'s limits");
- 8 KiB of a body, the most `SWW_WAF_CORE_RULE_SET_BODY_INSPECTION_SIZE` takes.
A request can reach all of these at once. At paranoia level 4, with no rule
switched off, the Core Rule Set takes under a second on one core of a current
server to inspect it. So `waf` answers it within the default 2 seconds, even
after the default 800 milliseconds of waiting for GeoJS. Enough such requests at
once can still overload `waf` past `SWW_RPROXY_WAF_BACKEND_TIMEOUT_MS`.
### The report