Skip to content

Latest commit

 

History

269 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Coraza WAF Caddy Module

Tests Project Status: Active – The project has reached a stable, usable state and is being actively developed.

OWASP Coraza Caddy Module provides Web Application Firewall capabilities for Caddy.

OWASP Coraza WAF is 100% compatible with OWASP Coreruleset and Modsecurity syntax.

CRS Documentation

If you’re looking for installation guidance, tuning, false-positive handling, or deployment best practices for CRS, refer to the official OWASP CRS documentation. https://coreruleset.org/docs/ This repository focuses on Coraza integration and runtime behavior rather than maintaining CRS rule documentation.

Getting started

go run mage.go -l lists all the available commands:

▶ go run mage.go -l
Targets:
  buildCaddy        builds the plugin.
  buildCaddyLinux   builds the plugin with GOOS=linux.
  buildExample       builds the example deployment.
  check              runs lint and tests.
  coverage           runs tests with coverage and race detector enabled.
  doc                runs godoc, access at http://localhost:6060
  e2e                runs e2e tests with a built plugin against the example deployment.
  format             formats code in this repository.
  ftw                runs CRS regressions tests.
  lint               verifies code quality.
  precommit          installs a git hook to run check when committing
  reloadExample      reload the test environment.
  runExample         spins up the test environment, access at http://localhost:8080.
  teardownExample    tears down the test environment.
  test               runs all tests.

Plugin syntax

coraza_waf {
 directives `
  Include /path/to/config.conf
  SecAction "id:1,pass,log"
 `
}

Sample usage:

Important: order coraza_waf first must be always included in your Caddyfile for Coraza module to work

{
    order coraza_waf first
}

http://127.0.0.1:8080 {
 coraza_waf {
  directives `
   SecAction "id:1,pass,log"
   SecRule REQUEST_URI "/test5" "id:2, deny, log, phase:1"
   SecRule REQUEST_URI "/test6" "id:4, deny, log, phase:3"
   Include file1.conf 
   Include file2.conf
   Include /some/path/*.conf
  `
 }
 reverse_proxy http://192.168.1.15:8080
}

Build Caddy with Coraza WAF

Run:

xcaddy build --with github.com/corazawaf/coraza-caddy/v2

Testing

You may run the test suite by executing:

go run mage.go test

Using OWASP Core Ruleset

You can load OWASP CRS by passing the field load_owasp_crs and then load the CRS files in the directives as described in the coraza-coreruleset documentation.

The @-prefixed paths are not files on disk. They are served from a ruleset that is compiled into the binary, and load_owasp_crs is what makes them resolvable. This has two consequences:

  • You do not need to download CRS, mount a volume, or ship rule files alongside the binary. xcaddy build --with github.com/corazawaf/coraza-caddy/v2 already contains them.
  • Do not put a filesystem path in front of an @ path. Include /etc/caddy/rules/@owasp_crs/*.conf will not work; the @ prefix must start the path.

If you use an @ path without load_owasp_crs, Caddy fails at startup with:

invalid WAF config from string: failed to readfile:
  open @coraza.conf-recommended: no such file or directory

Adding load_owasp_crs to the coraza_waf block resolves it.

:8080 {
 coraza_waf {
  load_owasp_crs
  directives `
   Include @coraza.conf-recommended
   Include @crs-setup.conf.example
   Include @owasp_crs/*.conf
   SecRuleEngine On
  `
 }

 reverse_proxy httpbin:8081
}

Specifying transaction ID from downstream

You can specify the transaction ID by setting the field tx_id_req_header and then pass the value for that request header. This is useful when running coraza behind another HTTP server and using the request ID issued by that server.

Important: tx_id_req_header must be set or overwritten only by a trusted upstream proxy, and that proxy must strip any client-provided value for the same header before it reaches coraza. Otherwise, clients can spoof the transaction ID (and any downstream consumers of it). Configure your front-end proxy to remove client-sent values and inject a trusted request ID instead.

:8080 {
 coraza_waf {
  load_owasp_crs
  directives `
   Include @coraza.conf-recommended
   Include @crs-setup.conf.example
   Include @owasp_crs/*.conf
   SecRuleEngine On
  `
  tx_id_req_header "X-Transaction-ID"
 }

 reverse_proxy httpbin:8081
}

Performance

Coraza memoizes the expensive parts of rule compilation (regex and aho-corasick pattern compilation) so identical patterns are not recompiled when several WAF instances in the same process share the same rules. This matters most when one Caddy process serves many sites that each load CRS.

Memoization is enabled by default. There is no flag to turn it on. The coraza.no_memoize build tag exists only to turn it off:

Build tag Behaviour
(none) Memoization enabled (default)
coraza.no_memoize Disabled — every pattern compiles fresh

Older guidance recommends building with -tags memoize_builders. That tag was how memoization was opted into up to Coraza v3.4.0, when the default was off. It was removed in v3.5.0 once memoization became the default. Go ignores unknown build tags silently, so passing it today neither fails nor does anything — drop it from your build.

The cache is global to the process, so entries are released when a WAF is destroyed. This module already does that: the pooled WAF is closed through caddy.Destructor when the last reference is released, which is what lets memory be reclaimed across config reloads.

Running Example

Docker

go run mage.go buildExample runExample
curl -i localhost:8080/

Local

# in terminal 1
go run github.com/mccutchen/go-httpbin/v2/cmd/go-httpbin@v2.9.0 -port 8081

# in terminal 2
go run mage.go buildCaddy
./build/caddy run --config example/Caddyfile --adapter caddyfile

# in terminal 3
curl -i localhost:8080/

Respond with custom message or HTML page

In order to respond with a custom message or HTML page, you can take advantage of handle_errors directive:

handle_errors 403 {
 header X-Blocked "true"
 respond "Your request was blocked. Request ID: {http.request.header.x-request-id}"
}

or

handle_errors {
 @block_codes `{err.status_code} in [403]`
 handle @block_codes {
  root    * /path/to/html/dir
  rewrite * /{err.status_code}.html
  file_server
 }
}

It is possible to use the templates directive to render data dynamically. Take a look at example/403.html file.

About

OWASP Coraza middleware for Caddy. It provides Web Application Firewall capabilities

Topics

Resources

Stars

677 stars

Watchers

16 watching

Forks

Releases

Packages

Used by

Contributors

Languages