check / check (push) Waiting to run
Every setting of discriminator and rproxy is read through viper, in place of the os.LookupEnv function Main passed down. NewViper turns AutomaticEnv and AllowEmptyEnv on, so a setting that is set but empty reads as set. A setting may also be given as a file, the _FILE form, which rproxy's settings now have too; rproxy still writes nothing to disk. The settings are renamed. Discriminator's take the prefix SWW_WAF_, rproxy's take SWW_RPROXY_, and the shared SWW_COMMAND keeps SWW_. The Core Rule Set's settings take SWW_WAF_CORE_RULE_SET_ rather than SWW_WAF_WAF_. Model: deepseek-v4-pro (first version); opus-5-5 (rework)
40 lines
1.1 KiB
Go
40 lines
1.1 KiB
Go
package discriminator
|
|
|
|
// The heuristic trap_paths. It reads SWW_WAF_TRAP_PATHS.
|
|
|
|
import (
|
|
"context"
|
|
"slices"
|
|
"time"
|
|
|
|
"sneak.berlin/go/smallwebwaf/internal/bans"
|
|
"sneak.berlin/go/smallwebwaf/internal/requestlog"
|
|
"sneak.berlin/go/smallwebwaf/internal/rules"
|
|
)
|
|
|
|
// trapPaths refuses a request for a path in SWW_WAF_TRAP_PATHS: its path as a
|
|
// path rule sees it, without the query, as sent or once percent-decoded, is one
|
|
// of them. Such a request is a clear sign of attack, as a ban rule's match is:
|
|
// it bans the client's netblock, or in observe mode raises the alert for the
|
|
// ban it would have made. The ban's notes give the path as sent, and so does
|
|
// its figure.
|
|
type trapPaths struct{}
|
|
|
|
func (trapPaths) name() string { return "trap_paths" }
|
|
|
|
func (trapPaths) check(_ context.Context, rq *request, now time.Time) *verdict {
|
|
path := rules.Path(rq.in)
|
|
if !slices.Contains(rq.h.config.TrapPaths, path) &&
|
|
!slices.Contains(rq.h.config.TrapPaths, rules.DecodeOnce(path)) {
|
|
return nil
|
|
}
|
|
|
|
rq.attack = true
|
|
rq.banForAttack(now, bans.Notes{TrapPath: path})
|
|
|
|
return &verdict{
|
|
action: requestlog.ActionBanned,
|
|
figures: map[string]any{"path": path},
|
|
}
|
|
}
|