Skip to content

GoFurry/coraza-fiber-lite

Repository files navigation

coraza-fiber-lite

Last Version License Go Version

Chinese | English

Lightweight Coraza WAF middleware for Fiber.

What it supports

  • Instance-based WAF engines for app-level or group-level registration
  • Request header and request body inspection
  • Custom block and error handling hooks
  • Custom block messages
  • Rule loading from the local filesystem or RootFS
  • Optional in-memory metrics collection per engine
  • Manual reload through the engine API

What it does not support

  • Response body inspection

Installation

go get github.com/GoFurry/coraza-fiber-lite/v2

Quick start

package main

import (
	"fmt"
	"log"

	corazalite "github.com/GoFurry/coraza-fiber-lite/v2"
	"github.com/gofiber/fiber/v3"
)

func main() {
	app := fiber.New()

	engine, err := corazalite.NewEngine(corazalite.CorazaCfg{
		DirectivesFile:    []string{"./conf/coraza.conf"},
		BlockMessage:      "Request blocked by CorazaLite WAF",
		RequestBodyAccess: true,
		RequestBodyLimit:  10 * 1024 * 1024,
		EnableErrorLog:    true,
	})
	if err != nil {
		log.Fatal(err)
	}

	app.Use(engine.Middleware())

	app.Get("/", func(c fiber.Ctx) error {
		return c.SendString("Hello, Fiber with CorazaLite WAF!")
	})

	app.Post("/submit", func(c fiber.Ctx) error {
		return c.JSON(fiber.Map{
			"message": fmt.Sprintf("Received name: %s", c.FormValue("name")),
		})
	})

	log.Fatal(app.Listen(":8080"))
}

Configuration

type CorazaCfg struct {
	DirectivesFile []string
	RootFS         fs.FS
	BlockMessage   string

	RequestBodyAccess        bool
	RequestBodyLimit         int
	RequestBodyInMemoryLimit int

	DebugLogger    debuglog.Logger
	EnableErrorLog bool
}

DirectivesFile is resolved against the process working directory by default. If RootFS is set, the middleware validates and loads those directive paths from the provided filesystem instead.

Engine API

import (
	"log"
	"strings"

	corazalite "github.com/GoFurry/coraza-fiber-lite/v2"
	"github.com/gofiber/fiber/v3"
)

engine, err := corazalite.NewEngine(corazalite.CorazaCfg{
	DirectivesFile:    []string{"./conf/coraza.conf"},
	RequestBodyAccess: true,
})
if err != nil {
	log.Fatal(err)
}

app.Use(engine.Middleware(corazalite.MiddlewareConfig{
	Skipper: func(c fiber.Ctx) bool {
		return strings.HasPrefix(c.Path(), "/healthz")
	},
	BlockHandler: func(c fiber.Ctx, details corazalite.InterruptionDetails) error {
		return c.Status(details.StatusCode).JSON(fiber.Map{
			"blocked": true,
			"rule_id": details.RuleID,
		})
	},
	ErrorHandler: func(c fiber.Ctx, mwErr corazalite.MiddlewareError) error {
		return c.Status(mwErr.StatusCode).JSON(fiber.Map{
			"error": mwErr.Code,
			"msg":   mwErr.Message,
		})
	},
}))

Upgrading to v2

v2 removes the previous package-level singleton helpers and built-in HTTP management endpoints.

  • Create an engine explicitly with NewEngine(...)
  • Mount middleware with engine.Middleware(...)
  • Build any admin or metrics routes yourself around engine.Reload(), engine.Snapshot(), and engine.Report()

The package is intentionally instance-first. It does not open admin or metrics routes for you; if you want operational endpoints, wire them yourself around the engine methods below:

  • engine.Reload()
  • engine.Snapshot()
  • engine.MetricsSnapshot()
  • engine.Report()

Example:

ops := app.Group("/ops")

ops.Get("/waf", func(c fiber.Ctx) error {
	return c.JSON(engine.Report())
})

ops.Post("/waf/reload", func(c fiber.Ctx) error {
	if err := engine.Reload(); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error": err.Error(),
		})
	}

	return c.JSON(engine.Snapshot())
})

Example directives

SecRuleEngine On
SecRequestBodyAccess On
SecRule REQUEST_HEADERS:Content-Type "^application/json" \
"id:210001,phase:1,pass,nolog,ctl:requestBodyProcessor=JSON"

SecRule REQBODY_ERROR "!@eq 0" \
"id:210002,phase:2,log,deny,status:400,msg:'Failed to parse request body',severity:2"

SecRule ARGS "@rx (?i)(union\s+select|or\s+1=1|<script|alert\()" \
"id:200001,phase:2,deny,status:403,msg:'Malicious payload detected'"

Examples

Run the basic example:

cd examples/basic
go run .

Try:

curl http://localhost:8080/
curl "http://localhost:8080/?id=1%20OR%201=1"

There is also a route-group example under examples/group-scoped with separate engines for /api/* and /admin/*.

References

License

This project is open-sourced under the MIT License.

About

A lightweight Coraza WAF middleware for Fiber 一个轻量级的 Fiber Coraza WAF 中间件

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages