feat(waf): CRS-App-Exclusion-Plugins (Nextcloud/WordPress/Drupal) pro Domain — v1.3.12
Statt manueller SecRuleRemoveById-IDs kann man pro Domain offizielle OWASP-CRS- Exclusion-Plugins aktivieren — pfad-genaue, upstream-gepflegte App-Ausnahmen. - Migration 0046: waf_configs.crs_plugins text[]. - Engine (engine.go): je gewähltem Plugin werden config/before VOR den CRS-Rules und after DANACH inkludiert (exakt nach OWASP-CRS-Plugin-Spec); nur die für DIESE Domain gewählten, nur wenn die Datei existiert. Whitelist KnownCRSPlugins. - Handler: crs_plugins im Upsert-Body + Whitelist-Validierung (Include-Pfad- Injection-Schutz). - Packaging (postinst): lädt die Plugins (coreruleset/<name>-plugin) nach <crs>/plugins/ — self-healing auf jedem configure, nur fehlende. - UI: Multi-Select „App-Profile (CRS-Plugins)" im WAF-Config-Drawer. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
60
internal/waf/engine_plugins_test.go
Normal file
60
internal/waf/engine_plugins_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package waf
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.netcell-it.de/projekte/edgeguard-native/internal/models"
|
||||
)
|
||||
|
||||
// mustWrite legt eine Datei (inkl. Verzeichnis) an.
|
||||
func mustWrite(t *testing.T, p, content string) {
|
||||
t.Helper()
|
||||
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(p, []byte(content), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDirectives_CRSPluginIncludeOrder(t *testing.T) {
|
||||
crs := t.TempDir()
|
||||
mustWrite(t, filepath.Join(crs, "crs-setup.conf"), "# setup\n")
|
||||
mustWrite(t, filepath.Join(crs, "rules", "REQUEST-942.conf"), "# rules\n")
|
||||
mustWrite(t, filepath.Join(crs, "plugins", "nextcloud-rule-exclusions-config.conf"), "# nc config\n")
|
||||
mustWrite(t, filepath.Join(crs, "plugins", "nextcloud-rule-exclusions-before.conf"), "# nc before\n")
|
||||
|
||||
cfg := models.WafConfig{Mode: "blocking", ParanoiaLevel: 1, CRSPlugins: []string{"nextcloud", "unknown-x"}}
|
||||
out := buildDirectives(cfg, crs)
|
||||
|
||||
iSetup := strings.Index(out, "crs-setup.conf")
|
||||
iCfg := strings.Index(out, "nextcloud-rule-exclusions-config.conf")
|
||||
iBefore := strings.Index(out, "nextcloud-rule-exclusions-before.conf")
|
||||
iRules := strings.Index(out, filepath.Join("rules", "*.conf"))
|
||||
if iSetup < 0 || iCfg < 0 || iBefore < 0 || iRules < 0 {
|
||||
t.Fatalf("erwartete Includes fehlen:\n%s", out)
|
||||
}
|
||||
// config + before MÜSSEN vor den CRS-Rules stehen (Plugin-Spec).
|
||||
if iSetup >= iCfg || iCfg >= iBefore || iBefore >= iRules {
|
||||
t.Errorf("falsche Include-Reihenfolge (setup=%d cfg=%d before=%d rules=%d):\n%s", iSetup, iCfg, iBefore, iRules, out)
|
||||
}
|
||||
// Unbekanntes Plugin darf NICHT inkludiert werden (Whitelist).
|
||||
if strings.Contains(out, "unknown-x") {
|
||||
t.Errorf("unbekanntes Plugin wurde inkludiert:\n%s", out)
|
||||
}
|
||||
// Nicht existente after.conf → keine Include-Zeile.
|
||||
if strings.Contains(out, "nextcloud-rule-exclusions-after.conf") {
|
||||
t.Errorf("nicht existente after.conf wurde inkludiert:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveCRSPlugins(t *testing.T) {
|
||||
got := resolveCRSPlugins([]string{"nextcloud", " wordpress ", "bogus", ""})
|
||||
want := "nextcloud-rule-exclusions,wordpress-rule-exclusions"
|
||||
if strings.Join(got, ",") != want {
|
||||
t.Errorf("resolveCRSPlugins=%v want %q", got, want)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user