check / check (push) Waiting to run
Every *.rules file in SWWAF_RULES_DIR is read at start and on each change. Each request is checked against the rules after the rate limits: log notes a match, block refuses with 403, ban refuses and bans the netblock for SWWAF_ATTACK_BAN_DURATION, made permanent by its next request or attack. path, query and uri are matched as the request line sent them; header:Host and header:Transfer-Encoding are refused. Bans gain a cause. The image ships 00-default.rules. Judgement call: a header sent twice is matched with its values joined by ", ". Judgement call: SWWAF_MAX_BAN_DURATION does not cap a ban for an attack. Not in this unit: offences for rule matches, with the error burst. Model: opus-5-5
41 lines
1.1 KiB
Go
41 lines
1.1 KiB
Go
package proxy
|
|
|
|
import (
|
|
"time"
|
|
|
|
"sneak.berlin/go/smallwebwaf/internal/requestlog"
|
|
"sneak.berlin/go/smallwebwaf/internal/rules"
|
|
)
|
|
|
|
// checkRules checks the request against the rules of the rule files at
|
|
// now, notes the ids of those it matches in the log line, and returns the
|
|
// action of the rule that refuses it, ActionRuleBlocked for a block rule
|
|
// and ActionBanned for a ban rule, or "" when none does. In enforce mode
|
|
// a ban rule bans the client's netblock for a clear sign of attack.
|
|
func (rq *request) checkRules(now time.Time) string {
|
|
matched := rq.h.rules.Match(rq.in)
|
|
|
|
for _, rule := range matched {
|
|
rq.line.RuleIDs = append(rq.line.RuleIDs, rule.ID)
|
|
rq.h.metrics.RuleMatched(rule.ID, rule.Action)
|
|
}
|
|
|
|
if len(matched) == 0 {
|
|
return ""
|
|
}
|
|
|
|
// Only the last rule matched can refuse the request.
|
|
switch last := matched[len(matched)-1]; last.Action {
|
|
case rules.ActionBlock:
|
|
return requestlog.ActionRuleBlocked
|
|
case rules.ActionBan:
|
|
if !rq.h.config.Observe {
|
|
rq.banForAttack(now, last)
|
|
}
|
|
|
|
return requestlog.ActionBanned
|
|
default:
|
|
return ""
|
|
}
|
|
}
|