feat(waf): benutzerdefinierte App-Profile + Fix: CRS-Plugins wurden im Agent nie geladen — v1.3.17

Neu: eigene WAF-App-Profile (benannte, wiederverwendbare Rule-ID-Ausnahme-
Bündel) — zentrale Bibliothek im UI (eigener Tab), pro Domain zuweisbar,
Built-in-OWASP-Plugins bleiben read-only + als Vorlage klonbar. Nur reine
Rule-IDs/Ranges (keine SecLang-Ausführung, injektionssicher).
- Migration 0047: Tabelle waf_app_profiles (repliziert via reconcile) +
  waf_configs.app_profiles.
- Service/Handler: CRUD (/waf/profiles), Built-ins geschützt (builtin=false-Gate).
- Agent-Loader: app_profiles → in effektive rule_exclusions gemerged; ihr
  updated_at hebt das effektive updated_at der Domain → Engine-Rebuild bei
  Profil-Edit.
- UI: Profile-Tab (Liste/Editor mit durchsuchbaren Rule-IDs) + Multi-Select im
  Domain-Drawer.

FIX (wichtig): ListAllWithDomain — der EINZIGE Loader des laufenden WAF-Agents —
selektierte crs_plugins nie. Dadurch war cfg.CRSPlugins im Agent immer leer und
KEIN Built-in-CRS-Plugin (Nextcloud/WordPress/Drupal) wurde je in die Engine
inkludiert. Jetzt geladen (+ app_profiles). Die per-Domain-Plugin-Wahl wirkt
damit erstmals tatsächlich.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-08-03 15:51:39 +02:00
parent 0846eaa05b
commit 5c268425c1
10 changed files with 776 additions and 20 deletions

View File

@@ -1880,7 +1880,11 @@
"deleteFailed": "Delete failed",
"secretSet": "Stored — leave empty to keep unchanged.",
"secretUnset": "Nothing stored yet.",
"tabs": { "settings": "Settings", "clients": "Clients (NAS)", "users": "Users" },
"tabs": {
"settings": "Settings",
"clients": "Clients (NAS)",
"users": "Users"
},
"settings": {
"enabled": "RADIUS active on this node",
"listen": "Listen addresses"
@@ -1951,11 +1955,15 @@
"exclusionAddPlaceholder": "Search rule (ID or description)…",
"exclusionAddNote": "Note (optional)",
"exclusionAddNotFound": "No rule found",
"exclusionAddBtn": "Add"
"exclusionAddBtn": "Add",
"appProfiles": "Custom App Profiles",
"appProfilesHint": "Reusable, self-maintained profiles (bundles of rule IDs) — create them centrally under “App Profiles” and assign them here per domain. Complements the OWASP plugins above.",
"appProfilesPlaceholder": "Select custom profiles (optional)"
},
"tabs": {
"domains": "Domains",
"alerts": "Alerts"
"alerts": "Alerts",
"profiles": "App Profiles"
},
"alerts": {
"total": "entries",
@@ -1984,6 +1992,39 @@
"exceptionModalHint": "Optional: describe why this rule is a false positive for this domain.",
"exceptionNotePlaceholder": "e.g. Our custom API uses non-standard headers that trigger this rule.",
"alreadyExcluded": "Already excluded"
},
"profiles": {
"intro": "Reusable exclusion profiles (bundles of CRS rule IDs). Create once, assign per domain. The built-in OWASP plugins are read-only and selected per domain.",
"new": "New Profile",
"empty": "No custom profiles yet. Create one to reuse rule exclusions.",
"builtinInfo": "Built-in OWASP CRS plugins (file-based, maintained). Read-only — selectable per domain in the WAF drawer. “Use as template” creates an empty custom profile from it to fill in.",
"typeBuiltin": "OWASP",
"typeCustom": "Custom",
"col": {
"name": "Name",
"type": "Type",
"description": "Description",
"rules": "Exclusions"
},
"edit": "Edit",
"delete": "Delete",
"clone": "Clone",
"asTemplate": "Use as template",
"deleteConfirm": "Really delete this profile? Domains using it will lose these exclusions.",
"createTitle": "New App Profile",
"editTitle": "Edit App Profile",
"name": "Name",
"namePlaceholder": "e.g. My WebApp",
"description": "Description",
"descriptionPlaceholder": "What is this profile for? (optional)",
"rules": "Rule Exclusions",
"rulesHint": "CRS rule IDs disabled for assigned domains. Searchable by ID or description.",
"rulesPlaceholder": "Search and add rule IDs…",
"saved": "Profile saved.",
"saveFailed": "Could not save profile.",
"deleted": "Profile deleted.",
"deleteFailed": "Could not delete profile.",
"cloneSuffix": "Copy"
}
}
}
}