Chinese | English
Lightweight Coraza WAF middleware for Fiber.
- 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
- Response body inspection
go get github.com/GoFurry/coraza-fiber-lite/v2package 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"))
}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.
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,
})
},
}))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(), andengine.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())
})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'"
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/*.
This project is open-sourced under the MIT License.