Fix rule parsing for single reverse proxies

This commit is contained in:
fuomag9
2026-03-04 21:16:11 +01:00
parent 77d3e35c63
commit 7341070c0d
14 changed files with 685 additions and 143 deletions
+40 -2
View File
@@ -2,7 +2,9 @@
import { useState } from "react";
import { useFormState } from "react-dom";
import { Alert, Box, Button, Card, CardContent, Checkbox, FormControl, FormControlLabel, FormLabel, MenuItem, Radio, RadioGroup, Stack, Switch, TextField, Typography } from "@mui/material";
import { Alert, Box, Button, Card, CardContent, Checkbox, Collapse, FormControl, FormControlLabel, FormLabel, MenuItem, Radio, RadioGroup, Stack, Switch, TextField, Typography } from "@mui/material";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import type {
GeneralSettings,
AuthentikSettings,
@@ -14,6 +16,7 @@ import type {
WafSettings
} from "@/src/lib/settings";
import { GeoBlockFields } from "@/src/components/proxy-hosts/GeoBlockFields";
import { WafRuleExclusions } from "@/src/components/proxy-hosts/WafRuleExclusions";
import {
updateCloudflareSettingsAction,
updateGeneralSettingsAction,
@@ -109,6 +112,8 @@ export default function SettingsClient({
const [syncState, syncFormAction] = useFormState(syncSlaveInstancesAction, null);
const [geoBlockState, geoBlockFormAction] = useFormState(updateGeoBlockSettingsAction, null);
const [wafState, wafFormAction] = useFormState(updateWafSettingsAction, null);
const [wafCustomDirectives, setWafCustomDirectives] = useState(globalWaf?.custom_directives ?? "");
const [wafShowTemplates, setWafShowTemplates] = useState(false);
const isSlave = instanceSync.mode === "slave";
const isMaster = instanceSync.mode === "master";
@@ -823,18 +828,51 @@ export default function SettingsClient({
</span>
}
/>
<WafRuleExclusions value={globalWaf?.excluded_rule_ids} />
<TextField
name="waf_custom_directives"
label="Custom SecLang Directives"
multiline
minRows={3}
maxRows={12}
defaultValue={globalWaf?.custom_directives ?? ""}
value={wafCustomDirectives}
onChange={(e) => setWafCustomDirectives(e.target.value)}
placeholder={`SecRule REQUEST_URI "@contains /secret" "id:9001,deny,status:403,log,msg:'Blocked path'"`}
inputProps={{ style: { fontFamily: "monospace", fontSize: "0.8rem" } }}
helperText="ModSecurity SecLang syntax. Applied after OWASP CRS if enabled."
fullWidth
/>
<Box>
<Button
size="small"
endIcon={<ExpandMoreIcon sx={{ transform: wafShowTemplates ? "rotate(180deg)" : "none", transition: "transform 0.2s" }} />}
onClick={() => setWafShowTemplates((v) => !v)}
sx={{ color: "text.secondary", textTransform: "none", px: 0 }}
>
Quick Templates
</Button>
<Collapse in={wafShowTemplates}>
<Stack spacing={0.75} mt={0.75}>
{[
{ label: "Allow IP", snippet: `SecRule REMOTE_ADDR "@ipMatch 1.2.3.4" "id:9000,phase:1,allow,nolog,msg:'Allow IP'"` },
{ label: "Disable WAF for path", snippet: `SecRule REQUEST_URI "@beginsWith /api/" "id:9001,phase:1,ctl:ruleEngine=Off,nolog"` },
{ label: "Remove XSS rules", snippet: `SecRuleRemoveByTag "attack-xss"` },
{ label: "Block User-Agent", snippet: `SecRule REQUEST_HEADERS:User-Agent "@contains badbot" "id:9002,phase:1,deny,status:403,log"` },
].map((t) => (
<Button
key={t.label}
size="small"
variant="outlined"
startIcon={<ContentCopyIcon fontSize="inherit" />}
onClick={() => setWafCustomDirectives((prev) => prev ? `${prev}\n${t.snippet}` : t.snippet)}
sx={{ justifyContent: "flex-start", textTransform: "none", fontFamily: "monospace", fontSize: "0.72rem" }}
>
{t.label}
</Button>
))}
</Stack>
</Collapse>
</Box>
<Alert severity="info" sx={{ fontSize: "0.8rem" }}>
WAF audit events are stored for 90 days and viewable under <strong>WAF Events</strong> in the sidebar.
Set mode to <em>Detection Only</em> first to observe traffic before enabling blocking.