mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-16 05:15:03 +00:00
feat(lib): implement request weight (#621)
* feat(lib): implement request weight Replaces #608 This is a big one and will be what makes Anubis a generic web application firewall. This introduces the WEIGH option, allowing administrators to have facets of request metadata add or remove "weight", or the level of suspicion. This really makes Anubis weigh the soul of requests. Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(lib): maintain legacy challenge behavior Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(lib): make weight have dedicated checkers for the hashes Signed-off-by: Xe Iaso <me@xeiaso.net> * feat(data): convert some rules over to weight points Signed-off-by: Xe Iaso <me@xeiaso.net> * docs: document request weight Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(CHANGELOG): spelling error Signed-off-by: Xe Iaso <me@xeiaso.net> * chore: spelling Signed-off-by: Xe Iaso <me@xeiaso.net> * docs: fix links to challenge information Signed-off-by: Xe Iaso <me@xeiaso.net> * docs(policies): fix formatting Signed-off-by: Xe Iaso <me@xeiaso.net> * fix(config): make default weight adjustment 5 Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net>
This commit is contained in:
@@ -402,13 +402,20 @@ func (s *Server) PassChallenge(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, redir, http.StatusFound)
|
||||
}
|
||||
|
||||
func cr(name string, rule config.Rule) policy.CheckResult {
|
||||
func cr(name string, rule config.Rule, weight int) policy.CheckResult {
|
||||
return policy.CheckResult{
|
||||
Name: name,
|
||||
Rule: rule,
|
||||
Name: name,
|
||||
Rule: rule,
|
||||
Weight: weight,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
weightOkayStatic = policy.NewStaticHashChecker("weight/okay")
|
||||
weightMildSusStatic = policy.NewStaticHashChecker("weight/mild-suspicion")
|
||||
weightVerySusStatic = policy.NewStaticHashChecker("weight/extreme-suspicion")
|
||||
)
|
||||
|
||||
// Check evaluates the list of rules, and returns the result
|
||||
func (s *Server) check(r *http.Request) (policy.CheckResult, *policy.Bot, error) {
|
||||
host := r.Header.Get("X-Real-Ip")
|
||||
@@ -421,6 +428,8 @@ func (s *Server) check(r *http.Request) (policy.CheckResult, *policy.Bot, error)
|
||||
return decaymap.Zilch[policy.CheckResult](), nil, fmt.Errorf("[misconfiguration] %q is not an IP address", host)
|
||||
}
|
||||
|
||||
weight := 0
|
||||
|
||||
for _, b := range s.policy.Bots {
|
||||
match, err := b.Rules.Check(r)
|
||||
if err != nil {
|
||||
@@ -428,11 +437,47 @@ func (s *Server) check(r *http.Request) (policy.CheckResult, *policy.Bot, error)
|
||||
}
|
||||
|
||||
if match {
|
||||
return cr("bot/"+b.Name, b.Action), &b, nil
|
||||
switch b.Action {
|
||||
case config.RuleDeny, config.RuleAllow, config.RuleBenchmark, config.RuleChallenge:
|
||||
return cr("bot/"+b.Name, b.Action, weight), &b, nil
|
||||
case config.RuleWeigh:
|
||||
slog.Debug("adjusting weight", "name", b.Name, "delta", b.Weight.Adjust)
|
||||
weight += b.Weight.Adjust
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cr("default/allow", config.RuleAllow), &policy.Bot{
|
||||
switch {
|
||||
case weight <= 0:
|
||||
return cr("weight/okay", config.RuleAllow, weight), &policy.Bot{
|
||||
Challenge: &config.ChallengeRules{
|
||||
Difficulty: s.policy.DefaultDifficulty,
|
||||
ReportAs: s.policy.DefaultDifficulty,
|
||||
Algorithm: config.DefaultAlgorithm,
|
||||
},
|
||||
Rules: weightOkayStatic,
|
||||
}, nil
|
||||
case weight > 0 && weight < 10:
|
||||
return cr("weight/mild-suspicion", config.RuleChallenge, weight), &policy.Bot{
|
||||
Challenge: &config.ChallengeRules{
|
||||
Difficulty: s.policy.DefaultDifficulty,
|
||||
ReportAs: s.policy.DefaultDifficulty,
|
||||
Algorithm: "metarefresh",
|
||||
},
|
||||
Rules: weightMildSusStatic,
|
||||
}, nil
|
||||
case weight >= 10:
|
||||
return cr("weight/extreme-suspicion", config.RuleChallenge, weight), &policy.Bot{
|
||||
Challenge: &config.ChallengeRules{
|
||||
Difficulty: s.policy.DefaultDifficulty,
|
||||
ReportAs: s.policy.DefaultDifficulty,
|
||||
Algorithm: "fast",
|
||||
},
|
||||
Rules: weightVerySusStatic,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return cr("default/allow", config.RuleAllow, weight), &policy.Bot{
|
||||
Challenge: &config.ChallengeRules{
|
||||
Difficulty: s.policy.DefaultDifficulty,
|
||||
ReportAs: s.policy.DefaultDifficulty,
|
||||
|
||||
Reference in New Issue
Block a user