coraza 0.1.0

Safe Rust bindings to OWASP Coraza WAF
docs.rs failed to build coraza-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

coraza-rs

Safe Rust bindings to OWASP Coraza Web Application Firewall, based on the official C bindings.

Coraza is a Go-based WAF compatible with ModSecurity's SecLang. This repository provides Rust crates to embed Coraza into Rust applications.

Crates

Crate Description
coraza Safe, idiomatic Rust API
coraza-sys Raw FFI bindings (auto-generated from C header)
examples Usage examples

Quick Start

use coraza::WafConfig;

fn main() {
    let waf = WafConfig::new()
        .unwrap()
        .with_directives("SecRuleEngine DetectionOnly")
        .with_directives("SecRequestBodyAccess On")
        .build()
        .unwrap();

    let mut tx = waf.new_transaction();

    tx.process_connection("127.0.0.1", 8080, "localhost", 80).unwrap();
    tx.process_uri("/path", "GET", "HTTP/1.1").unwrap();
    tx.add_request_header("Host", "localhost");
    tx.process_request_headers().unwrap();
    tx.process_logging();

    if let Some(intervention) = tx.intervention() {
        eprintln!("Blocked with status {}", intervention.status);
    }
}

Build Requirements

  • Rust 1.75+ (edition 2021)
  • Go 1.21+ (for compiling the Coraza WAF engine)
  • C compiler (gcc/clang on Unix, MSVC on Windows)
  • libclang (for bindgen)

On Ubuntu/Debian:

sudo apt install golang-go libclang-dev

On macOS:

brew install go llvm

Building

cargo build

The first build compiles the Go WAF engine into a static library and generates Rust FFI bindings. Subsequent builds are fast.

Examples

cargo run --bin simple_get
cargo run --bin deny_rule
cargo run --bin with_callbacks

simple_get

Minimal WAF usage with DetectionOnly mode — processes a GET request and checks for interventions.

deny_rule

WAF with a deny rule that blocks requests from specific IPs — demonstrates handling a 403 intervention.

with_callbacks

Registers debug log and error callbacks — shows how to capture matched rule details.

API Overview

Configuration

use coraza::{WafConfig, LogLevel};

let waf = WafConfig::new()?
    .with_directives("SecRuleEngine On")
    .with_directives("SecRequestBodyAccess On")
    .with_debug_log_callback(|level, msg, fields| {
        eprintln!("[{level}] {msg} {fields}");
    })
    .with_error_callback(|rule| {
        eprintln!("Rule {} matched: {}", rule.rule_id, rule.message);
    })
    .build()?;

Transaction Processing

Transactions follow Coraza's phase-based lifecycle:

let mut tx = waf.new_transaction();

// Phase 0: Connection & URI
tx.process_connection("127.0.0.1", 8080, "localhost", 80)?;
tx.process_uri("/path", "GET", "HTTP/1.1")?;

// Phase 1: Request headers
tx.add_request_header("Host", "localhost");
tx.process_request_headers()?;  // may return Err(Intervention)

// Phase 2: Request body (if SecRequestBodyAccess On)
tx.append_request_body(b"hello=world")?;
tx.process_request_body()?;

// Phase 3: Response headers
tx.process_response_headers(200, "HTTP/1.1")?;

// Phase 4: Response body (if SecResponseBodyAccess On)
tx.append_response_body(b"<html>...</html>")?;
tx.process_response_body()?;

// Phase 5: Logging (always run, even on interruption)
tx.process_logging();

// Check for rule matches
if let Some(intervention) = tx.intervention() {
    eprintln!("Blocked: {}", intervention.status);
}

Thread Safety

Type Send Sync Notes
Waf Yes Yes Immutable after creation; safe to share for concurrent transaction creation
WafConfig Yes No Builder consumed by build()
Transaction Yes No Mutable state; must not be shared across threads

License

Licensed under the Apache License, Version 2.0.