Coraza WAF Documentation

repository·main·Indexed 25 days ago

https://github.com/corazawaf/coraza

Coraza is an open-source, high-performance Web Application Firewall (WAF) written in Go. It is designed as a library that supports ModSecurity SecLang rulesets and is fully compatible with the OWASP Core Rule Set (CRS) v4. It provides integrations for Caddy, Proxy WASM, HAProxy, and a C Library, and includes features for audit logging, request/response body buffering, and memoization of expensive function calls.

Tokens
3.5K
Snippets
8
Records
21
Agent score
86%

What's inside Coraza

  1. Available Coraza Integrations

    main

    Coraza provides several implementations and plugins for different server environments:

    • Caddy: Caddy Reverse Proxy and Webserver Plugin (stable)
    • Proxy WASM: Extension for proxies with proxy-wasm support like Envoy (stable, under development)
    • HAProxy: SPOE Plugin (experimental)
    • C Library: For use with nginx, etc. (experimental)
    • RuiQi WAF: Web management panel and enhanced traffic control for Coraza SPOA (experimental)
  2. Development commands with Mage

    main

    Coraza uses mage.go for development tasks. You can list all available targets using go run mage.go -l.

    Common commands:

    • go run mage.go check: Runs lint and tests.
    • go run mage.go coverage: Runs tests with coverage and race detector enabled.
    • go run mage.go doc: Runs godoc.
    • go run mage.go format: Formats code in the repository.
    • go run mage.go fuzz: Runs fuzz tests.
    • go run mage.go lint: Verifies code quality.
    • go run mage.go precommit: Installs a git hook to run check on commit.
    • go run mage.go test: Runs all tests.
    go run mage.go format
  3. Manage memoization for expensive function calls

    main

    Coraza uses memoization to cache expensive function calls, specifically regex and aho-corasick compilation. This prevents recompiling the same patterns when multiple WAF instances in the same process share rules.

    Memoization is enabled by default and utilizes a global cache within the process.

    To prevent memory leaks in long-lived processes that frequently reload WAF configurations, you must release cached entries when a WAF is destroyed by calling WAF.Close() (utilizing experimental.WAFCloser).

  4. Configure Coraza using environment variables

    main

    The HTTP-Server example allows customization of WAF rules and response content via environment variables:

    • DIRECTIVES_FILE: Path to a custom Coraza directives file (e.g., .conf).
    • RESPONSE_BODY: Sets the response body content (useful for testing rules that match response bodies).
    • RESPONSE_HEADERS: Sets custom response headers.
  5. Run Coraza E2E Tests

    main

    You can run end-to-end tests using the http/e2e utility. You can run it as a standalone CLI tool against your own WAF deployment or import it as a library in your Go tests.

    go run github.com/corazawaf/coraza/v3/http/e2e/cmd/httpe2e@main --proxy-hostport localhost:8080 --httpbin-hostport localhost:8081
  6. Integrate Coraza as a Go library

    main

    Coraza can be used as a library within your Go programs to implement security middleware or integrate it with existing webservers. You can initialize a WAF instance using coraza.NewWAF with a configuration that includes SecLang directives, create transactions, and process request phases.

    package main
    
    import (
    	"fmt"
    
    	"github.com/corazawaf/coraza/v3"
    )
    
    func main() {
    	// First we initialize our waf and our seclang parser
    	waf, err := coraza.NewWAF(coraza.NewWAFConfig().
    		WithDirectives(`SecRule REMOTE_ADDR "@rx .*" "id:1,phase:1,deny,status:403"`))
    	// Now we parse our rules
    	if err != nil {
    		fmt.Println(err)
    	}
    
    	// Then we create a transaction and assign some variables
    	tx := waf.NewTransaction()
    	defer func() {
    		tx.ProcessLogging()
    		tx.Close()
    	}()
    	tx.ProcessConnection("127.0.0.1", 8080, "127.0.0.1", 12345)
    
    	// Finally we process the request headers phase, which may return an interruption
    	if it := tx.ProcessRequestHeaders(); it != nil {
    		fmt.Printf("Transaction was interrupted with status %d\n", it.Status)
    	}
    }
  7. Configure request body buffering limits

    main

    Coraza uses a two-stage buffering process to inspect request bodies before they reach upstream services. To prevent Denial of Service (DoS) attacks such as Out-of-Memory (OOM) errors or disk exhaustion, you must configure these limits carefully.

    1. Memory Buffering

    Coraza first attempts to buffer the body in memory.

    • Directive: SecRequestBodyMemoryLimit
    • Default Value: 131072 (bytes)
    • Risk: Setting this too high can cause the entire process to crash due to OOM, as there are no soft/hard limits on total memory consumption for buffering.
    • Recommendation: Keep the default value or lower.

    2. Disk Buffering

    If the body exceeds the memory limit, Coraza buffers the payload to disk.

    • Directive: SecRequestBodyLimit
    • Default Value: 13107200 (bytes)
    • Risk: Large payloads can fill up the host's disk space, degrading system performance.
    • Mitigation: Use SecRequestBodyLimitAction reject to ensure that once the limit is reached, the request is rejected and no further bytes are written to the disk. The buffered file is deleted once the request is finished.
  8. Test Coraza WAF behavior with curl

    main

    Once the server is running, you can test different request scenarios using curl:

    • True Positive (403 Forbidden): Trigger a rule violation (e.g., by passing an ID parameter).
    • True Negative (200 OK): A standard request that does not trigger rules.
    • Response Body Matching: If RESPONSE_BODY is configured, you can test rules that inspect the response body.
    # True positive request (403 Forbidden)
    curl -i 'localhost:8090/hello?id=0'
    
    # True negative request (200 OK)
    curl -i 'localhost:8090/hello'
    
    # True positive request (403 Forbidden) due to matching response body
    curl -i 'localhost:8090/hello'