Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ Pass them comma-separated:

## Deny behavior and logging

Every generated rule uses the `block` action, so the actual disruptive
behavior is decided in one place: the `SecDefaultAction` emitted at the top of
`mainconfig.conf`. `denyAction`/`denyStatus`/`denyRedirectUrl` control that
line:
When the engine config is emitted (the default), every generated rule uses the
`block` action, so the actual disruptive behavior is decided in one place: the
`SecDefaultAction` emitted at the top of `mainconfig.conf`.
`denyAction`/`denyStatus`/`denyRedirectUrl` control that line (and, when the
engine config is omitted, the inline action described below):

```bash
# Return 429 instead of 403
Expand All @@ -51,8 +52,12 @@ line:

If your ModSecurity/Coraza deployment already configures the engine (rule
engine mode, body access, default action), generate only the rules with
`includeEngineConfig=false` — your existing `SecDefaultAction` then decides
what blocking means.
`includeEngineConfig=false`. Because there is then no `SecDefaultAction` of
ours for `block` to inherit — and a host ruleset such as the OWASP Core Rule
Set defaults phase 2 to `pass` — the generated rules emit the disruptive action
(from `denyAction`/`denyStatus`) **inline** instead of `block`, so they still
deny (or, with `denyAction=pass`, run detection-only) regardless of the host's
default action.

## Engine flavors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,14 @@ public void processOpts() {
// Real boolean for the mustache section; derived strings so templates stay flat
additionalProperties.put("includeEngineConfig", includeEngineConfig);
additionalProperties.put("logAction", enableLogging ? "log,auditlog" : "nolog");
additionalProperties.put("denyActionDirective", buildDenyActionDirective());
String denyActionDirective = buildDenyActionDirective();
additionalProperties.put("denyActionDirective", denyActionDirective);
// Per-rule disruptive action. When the engine config is included, rules keep
// the bare `block`, which inherits the emitted SecDefaultAction. When it is
// omitted (rules layered onto a host engine, e.g. Coraza+CRS), there is no
// SecDefaultAction of ours to inherit — and a host like CRS defaults phase 2
// to `pass` — so emit the deny action inline instead, or the rules no-op.
additionalProperties.put("ruleDisruptiveAction", includeEngineConfig ? "block" : denyActionDirective);
}

/**
Expand Down Expand Up @@ -1546,6 +1553,7 @@ public Modsecurity3Generator() {
additionalProperties.put("includeEngineConfig", includeEngineConfig);
additionalProperties.put("logAction", "log,auditlog");
additionalProperties.put("denyActionDirective", "deny,status:" + denyStatus);
additionalProperties.put("ruleDisruptiveAction", includeEngineConfig ? "block" : "deny,status:" + denyStatus);
cliOptions.add(new CliOption("denyAction",
"Disruptive action applied when a rule blocks: 'deny', 'drop', 'redirect' or 'pass' (detection-only)")
.defaultValue(denyAction));
Expand Down
Loading