The Core Rule Set, run by Coraza, on each request's method, URL and headers (closes #25)
check / check (push) Waiting to run
check / check (push) Waiting to run
Coraza v3.8.1 runs the Core Rule Set 4.25.0 (coraza-coreruleset v4.25.0) after the rule files, with the six changes and the default SWWAF_WAF_DISABLED_RULES that SPEC.md gives; no body, no response. SWWAF_WAF_MODE, SWWAF_WAF_PARANOIA_LEVEL, SWWAF_WAF_ANOMALY_THRESHOLD and SWWAF_WAF_EXEMPT_PATHS as specified; SWWAF_WAF_DISABLED_RULES refuses 900000 to 900999, smallwebwaf's own rules among them. A request with more query parameters than Coraza reads, 1000, adds 5 (rule 900300). In block mode a match is refused with 403, an offence counted toward the error burst; in detect mode it is let through. Both log waf_rule_ids, waf_score and duration_waf, raise waf_block, and count smallwebwaf_waf_matches_total. Judgement call: waf_block is raised in block mode too. Deviation: no engine-error path; with no body read, Coraza cannot fail. Model: opus-5-5
This commit is contained in:
+26
-20
@@ -65,10 +65,10 @@ type request struct {
|
||||
counted bool
|
||||
limitPercent, bytesPercent percentage
|
||||
// attack is true for a request that matched a ban rule or asked for a
|
||||
// trap path, ruleBlocked for one a block rule refused, and
|
||||
// tokenRefused for one refused for a missing or wrong token, each an
|
||||
// offence its client's history counts.
|
||||
attack, ruleBlocked, tokenRefused bool
|
||||
// trap path, ruleBlocked for one a block rule refused, wafBlocked for
|
||||
// one the Core Rule Set refused, and tokenRefused for one refused for a
|
||||
// missing or wrong token, each an offence its client's history counts.
|
||||
attack, ruleBlocked, wafBlocked, tokenRefused bool
|
||||
// blocklisted is true once a blocklist is found to list the client,
|
||||
// dnsblListed once a DNSBL zone's verdict is, and abuseIPDBHit once
|
||||
// AbuseIPDB's score of it is a hit.
|
||||
@@ -190,11 +190,11 @@ func requestHeaders(r *http.Request, names []string) map[string]string {
|
||||
// check is the one place where a request can be refused once its client
|
||||
// is known, before its body is read or anything reaches the app. It
|
||||
// returns nil to let the request through. The checks of checkClient come
|
||||
// first, answered with SWWAF_BAN_RESPONSE, or 403 for a block rule, and
|
||||
// then the size limit, so that a request the rate limits count is counted
|
||||
// even when it is refused for its size. In observe mode a request
|
||||
// checkClient refuses goes on to the size limit like any other. ctx is
|
||||
// the request's own context.
|
||||
// first, answered with SWWAF_BAN_RESPONSE, or 403 for a block rule or the
|
||||
// Core Rule Set, and then the size limit, so that a request the rate
|
||||
// limits count is counted even when it is refused for its size. In
|
||||
// observe mode a request checkClient refuses goes on to the size limit
|
||||
// like any other. ctx is the request's own context.
|
||||
func (rq *request) check(ctx context.Context) *refusal {
|
||||
action := rq.checkClient(ctx)
|
||||
|
||||
@@ -203,7 +203,7 @@ func (rq *request) check(ctx context.Context) *refusal {
|
||||
case rq.h.config.Observe:
|
||||
// The log line names what enforce mode would have done.
|
||||
rq.line.WouldAction = action
|
||||
case action == requestlog.ActionRuleBlocked:
|
||||
case action == requestlog.ActionRuleBlocked || action == requestlog.ActionWAFBlocked:
|
||||
return &refusal{status: http.StatusForbidden, action: action}
|
||||
default:
|
||||
return rq.banResponse(action)
|
||||
@@ -233,9 +233,9 @@ func (rq *request) check(ctx context.Context) *refusal {
|
||||
// rate limits, unless the client is in SWWAF_RATE_LIMIT_EXEMPT_NETS or the
|
||||
// request's path is exempt under SWWAF_RATE_LIMIT_EXEMPT_PATHS, so that
|
||||
// every other request is counted, each of them by the client's limit
|
||||
// percentages, then SWWAF_TRAP_PATHS, and last the rule files. A request
|
||||
// exempt from the rate limits is exempt from the byte limits too. ctx is
|
||||
// the request's own context.
|
||||
// percentages, then SWWAF_TRAP_PATHS, then the rule files, and last the
|
||||
// Core Rule Set. A request exempt from the rate limits is exempt from the
|
||||
// byte limits too. ctx is the request's own context.
|
||||
func (rq *request) checkClient(ctx context.Context) string {
|
||||
cfg := rq.h.config
|
||||
if isInside(rq.client, cfg.AllowNets) {
|
||||
@@ -286,15 +286,20 @@ func (rq *request) checkClient(ctx context.Context) string {
|
||||
return requestlog.ActionBanned
|
||||
}
|
||||
|
||||
return rq.checkRules(now)
|
||||
action := rq.checkRules(now)
|
||||
if action != "" {
|
||||
return action
|
||||
}
|
||||
|
||||
return rq.checkCoreRuleSet()
|
||||
}
|
||||
|
||||
// pathExempt reports whether the rate limits leave out a request for u
|
||||
// because of SWWAF_RATE_LIMIT_EXEMPT_PATHS: whether its path as sent, the
|
||||
// path the app receives, not percent-decoded, starts with one of
|
||||
// prefixes, so that /%61ssets/x is not under /assets/ for an app whose
|
||||
// router matches the path as received. A request whose decoded path
|
||||
// contains .. anywhere or a backslash, or whose path as sent holds an
|
||||
// pathExempt reports whether a request for u is exempt under prefixes,
|
||||
// SWWAF_RATE_LIMIT_EXEMPT_PATHS or SWWAF_WAF_EXEMPT_PATHS: whether its
|
||||
// path as sent, the path the app receives, not percent-decoded, starts
|
||||
// with one of prefixes, so that /%61ssets/x is not under /assets/ for an
|
||||
// app whose router matches the path as received. A request whose decoded
|
||||
// path contains .. anywhere or a backslash, or whose path as sent holds an
|
||||
// encoded slash (%2F or %2f), never is, since an app may act on it as a
|
||||
// path outside every prefix: /assets/..%2Flogin as /login, or /assets%2Fx
|
||||
// as one path segment, as Go's router does.
|
||||
@@ -562,6 +567,7 @@ func (rq *request) addToHistory() {
|
||||
BrokeLimit: rq.line.Offence == requestlog.OffenceLimit,
|
||||
Attack: rq.attack,
|
||||
RuleBlocked: rq.ruleBlocked,
|
||||
WAFBlocked: rq.wafBlocked,
|
||||
TokenRefused: rq.tokenRefused,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user