engine

package
v0.4.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package engine provides SQL token fingerprints and contextual XSS detection. The SQL path is a pure Go approximation of libinjection's fingerprint approach.

Package engine provides HTTP protocol enforcement and smuggling detection. Checks observable framing conflicts, invalid protocol fields, and header injection. net/http owns raw chunk framing/size validation before handlers see a request.

Package engine provides sandboxed execution guards for the detection pipeline. All detector invocations are protected against ReDoS, memory exhaustion, and panics.

Package engine defines core interfaces for the WAF detection pipeline.

Index

Constants

View Source
const (
	// MaxDecodedBytes limits post-decompression/decoding expansion.
	MaxDecodedBytes = 2 * 1024 * 1024 // 2MB
	// MaxRegexMatchTime is the deadline for any single regex match.
	MaxRegexMatchTime = 50 * time.Millisecond

	// MaxRegexComplexityScore rejects patterns likely to cause catastrophic backtracking.
	MaxRegexComplexityScore = 30
)

Variables

View Source
var (
	// ErrRegexMatchTimeout and ErrRegexMatchOverload let callers that need
	// fail-closed accounting distinguish an incomplete match from a clean
	// negative result. The legacy bool methods retain their compatibility shape.
	ErrRegexMatchTimeout  = errors.New("regular expression match timed out")
	ErrRegexMatchOverload = errors.New("regular expression matcher overloaded")
)
View Source
var ErrDetectionOverload = errors.New("detection overload: too many in-flight guards")

ErrDetectionOverload reports that Guard could not start detector work because every bounded worker slot was already occupied.

View Source
var ErrRequestBodyReadOverload = errors.New("request body inspection overloaded")

ErrRequestBodyReadOverload means bounded reader or body-byte capacity is full. It is an incomplete-inspection condition and must never be treated as clean.

View Source
var ErrRequestBodyReadTimeout = errors.New("request body read idle timeout")

ErrRequestBodyReadTimeout means an upload stopped making progress. Upload time is bounded separately from the detector CPU budget.

View Source
var ErrRequestBodyTooLarge = errors.New("request body exceeds configured limit")

Functions

func ClientIP

func ClientIP(r *http.Request) string

func ClientIPWithTrustedProxies

func ClientIPWithTrustedProxies(r *http.Request, trustedCIDRs []string) string

ClientIPWithTrustedProxies accepts only the standardized forwarding chain. Provider-specific headers require ClientIPWithTrustedProxyProviders.

func ClientIPWithTrustedProxyProviders

func ClientIPWithTrustedProxyProviders(r *http.Request, trustedCIDRs []string, providerCIDRs map[string][]string) string

ClientIPWithTrustedProxyProviders resolves provider-specific headers only when the socket peer matches that provider's explicitly configured CIDRs.

func Guard

func Guard[T any](fn func() (T, error)) (result T, err error)

Guard runs a detection function with panic recovery and timeout protection. It is the compatibility wrapper for callers without a context; request paths should prefer GuardContext so cancellation can end the wait early.

func GuardContext

func GuardContext[T any](ctx context.Context, fn func() (T, error)) (result T, err error)

GuardContext runs a detector with panic recovery, a caller deadline (or a compatibility timeout when none is set), and caller cancellation. The detector runs in a bounded goroutine so a function that ignores ctx cannot hold the request path past its budget. When the caller returns early, the guard slot remains occupied until the detector exits; this preserves the leak bound enforced by guardSlots.

A nil context is treated like context.Background for compatibility with callers that do not have a request scope.

func GuardSync

func GuardSync[T any](fn func() (T, error)) (result T, err error)

GuardSync protects a non-blocking detector without creating a goroutine or timer. The caller's pipeline context still enforces the request deadline.

func NormalizeRequestPath

func NormalizeRequestPath(raw string) (string, bool)

NormalizeRequestPath cleans a URL path for security policy matching. It repeatedly URL-decodes (up to a safe cap), then path.Clean, ensures a leading "/", and rejects empty paths, NUL bytes, residual encodings, and residual ".." segments after cleaning.

func PathMatchesPrefix

func PathMatchesPrefix(requestPath, prefix string) bool

PathMatchesPrefix reports whether requestPath equals prefix or is a child under prefix using segment boundaries. Trailing slashes on prefix are ignored except that "/" matches every absolute path. Empty prefix matches all paths.

Examples: prefix "/api" or "/api/" matches "/api" and "/api/foo" but not "/apixyz".

func ProcessBudgetExhaustedPass

func ProcessBudgetExhaustedPass() uint64

ProcessBudgetExhaustedPass returns the number of budget-exhausted requests forwarded upstream for this process lifetime.

func RecordBudgetExhaustedPass

func RecordBudgetExhaustedPass()

RecordBudgetExhaustedPass records one request that was forwarded upstream after the detection budget ran out. The proxy calls this from the explicit ActionLog branch so that "allow" stays a decision rather than a fallthrough.

func RegexComplexityScore

func RegexComplexityScore(pattern string) int

RegexComplexityScore estimates the backtracking risk of a regex pattern. Higher score = more dangerous. Based on OWASP ReDoS detection heuristics.

func ResetBudgetExhaustedPassForTest

func ResetBudgetExhaustedPassForTest()

ResetBudgetExhaustedPassForTest clears the process counter for isolated tests. Used by the proxy's fail-open tests, which assert on an exact count.

func SQLLibinjectionFingerprint

func SQLLibinjectionFingerprint(input string) (string, bool)

SQLLibinjectionFingerprint tokenizes an SQL string and returns a fingerprint string. Returns empty string if the input doesn't look like SQL. If the fingerprint matches known SQLi patterns, the input is SQLi.

func SecurityPathViews added in v0.4.5

func SecurityPathViews(raw string) ([]string, bool)

SecurityPathViews preserves existing raw/clean policy meanings and adds the routing interpretation used by backends that strip matrix parameters. Use every view for protective requirements, not to broaden allowlist exemptions.

func SemanticQueueStats added in v0.4.5

func SemanticQueueStats() (jobs, waitNanos, overloads uint64, depth int)

SemanticQueueStats exposes cumulative queue delay and admission failures. Latency is measured before detector execution, independently of CPU work.

func SetDetectionBudgetExhaustedHook

func SetDetectionBudgetExhaustedHook(hook func())

SetDetectionBudgetExhaustedHook installs an optional metrics hook without introducing an import cycle with semantic metrics.

func XSSLibinjectionFingerprint

func XSSLibinjectionFingerprint(input string) bool

XSSLibinjectionFingerprint retains the historical API name but performs context-aware substring matching; it is not a token fingerprint implementation.

Types

type Action

type Action int

Action represents the action to take when a detection matches. 检测匹配后的动作。

const (
	// ActionPass allows the request to continue. 放行请求。
	ActionPass Action = iota
	// ActionBlock blocks the request. 拦截请求。
	ActionBlock
	// ActionChallenge presents a challenge (JS/CAPTCHA). 发起人机验证。
	ActionChallenge
	// ActionLog logs the request but allows it. 仅记录,不拦截。
	ActionLog
)

func (Action) String

func (a Action) String() string

type BoundedRegex

type BoundedRegex struct {
	// contains filtered or unexported fields
}

BoundedRegex wraps a regexp.Regexp with timeout protection for ReDoS.

func CompileSafe

func CompileSafe(pattern string) (*BoundedRegex, error)

CompileSafe compiles a regex pattern and rejects dangerously complex ones.

func (*BoundedRegex) Match

func (b *BoundedRegex) Match(b2 []byte) bool

Match performs bounded matching on a byte slice with ReDoS protection.

func (*BoundedRegex) MatchStatus

func (b *BoundedRegex) MatchStatus(b2 []byte) (bool, error)

MatchStatus is the byte-slice counterpart of MatchStringStatus.

func (*BoundedRegex) MatchString

func (b *BoundedRegex) MatchString(s string) bool

MatchString performs a complete RE2 match. Go's regexp engine has linear complexity; callers choosing the explicit deadline API must use Status and handle its error instead of silently treating an incomplete match as false.

func (*BoundedRegex) MatchStringStatus

func (b *BoundedRegex) MatchStringStatus(s string) (bool, error)

MatchStringStatus performs the complete match without truncating the subject. Go's regexp engine is RE2-based and linear-time; truncation here would create a security bypass whenever a payload is appended after the old cutoff. Callers that need to surface an incomplete inspection should use the returned error.

func (*BoundedRegex) Regexp

func (b *BoundedRegex) Regexp() *regexp.Regexp

Regexp returns the compiled stdlib pattern behind the bounded wrapper.

CompileSafe is also a construction-time gate: callers that must keep stdlib match semantics (no input truncation, no deadline) use Regexp to run the match themselves while still requiring the complexity gate up front. That matters for detectors, where silently truncating the subject would let an attacker append a payload past the truncation point.

type DetectionResult

type DetectionResult struct {
	Detected   bool     `json:"detected"`    // 是否检测到威胁 / Whether a threat was detected
	DetectorID string   `json:"detector_id"` // 检测器标识 / Detector identifier
	Category   string   `json:"category"`    // 攻击类别 (sqli/xss/rce/lfi...) / Attack category
	Severity   Severity `json:"severity"`    // 严重程度 / Severity level
	Action     Action   `json:"action"`      // 建议动作 / Recommended action
	Message    string   `json:"message"`     // 人类可读描述 / Human-readable description
	Confidence float64  `json:"confidence"`  // 置信度 0.0-1.0 / Confidence score
	Payload    string   `json:"payload"`     // 触发的恶意载荷 / Malicious payload that triggered detection
}

DetectionResult holds the result of a single detector's analysis. 单个检测器的分析结果。

type Detector

type Detector interface {
	// ID returns the unique identifier for this detector.
	// 返回检测器的唯一标识。
	ID() string

	// Name returns a human-readable name.
	// 返回人类可读的名称。
	Name() string

	// Detect analyzes the request context and returns detection results.
	// 分析请求上下文并返回检测结果。
	Detect(ctx context.Context, reqCtx *RequestContext) (*DetectionResult, error)

	// Priority returns the execution order (lower = earlier).
	// 返回执行优先级(数值越小越先执行)。
	Priority() int
}

Detector is the core interface for all WAF detection modules. Each layer in the detection pipeline implements this interface. 所有 WAF 检测模块的核心接口,检测流水线的每一层都实现此接口。

type Pipeline

type Pipeline struct {
	// contains filtered or unexported fields
}

func NewPipeline

func NewPipeline(detectors ...Detector) *Pipeline

func (*Pipeline) Add

func (p *Pipeline) Add(detector Detector)

func (*Pipeline) Detect

func (p *Pipeline) Detect(ctx context.Context, reqCtx *RequestContext) (*DetectionResult, error)

func (*Pipeline) DetectionBudget added in v0.4.5

func (p *Pipeline) DetectionBudget(reqCtx *RequestContext) time.Duration

DetectionBudget returns the effective analysis budget without starting it. Callers inspecting multiple identities can share this same bounded budget.

func (*Pipeline) Detectors

func (p *Pipeline) Detectors() []Detector

func (*Pipeline) SetDetectionBudget added in v0.4.5

func (p *Pipeline) SetDetectionBudget(budget time.Duration)

SetDetectionBudget sets the CPU analysis budget, excluding body upload time. The bounded ceiling avoids accidentally retaining detector workers forever.

type ProtocolViolation

type ProtocolViolation struct {
	Detected   bool
	Type       string // smuggling, chunked_abuse, encoding_abuse, header_injection
	Severity   Severity
	Confidence float64
	Message    string
}

ProtocolViolation holds detected protocol-level violations.

func DetectProtocolViolations

func DetectProtocolViolations(r *http.Request) *ProtocolViolation

DetectProtocolViolations checks the HTTP request for protocol-level attacks.

type RequestContext

type RequestContext struct {
	Request  *http.Request // 原始 HTTP 请求 / Original HTTP request
	ClientIP string        // 客户端真实 IP / Real client IP
	TraceID  string        // 溯源 ID / Trace ID for block pages
	SiteID   string        // 站点 ID / Site identifier
	// NormalizedPath is the canonical path used by security policies.
	NormalizedPath string
	// HostValidated is true only after the caller has matched Request.Host to
	// an allowed site/tenant. Request-aware same-origin optimizations must not
	// trust a raw, attacker-controlled Host value without this provenance.
	HostValidated bool
	// TrustedProxyCIDRs carries the immutable proxy trust scope used for
	// request-aware protocol decisions (for example X-Forwarded-Proto).
	TrustedProxyCIDRs []string
	DecodedURI        string            // 解码后的 URI / Decoded URI
	DecodedBody       []byte            // 解码后的请求体 / Decoded request body
	Results           []DetectionResult // 检测结果集合 / Detection results
	Metadata          map[string]any    // 扩展元数据 / Extension metadata
	// contains filtered or unexported fields
}

RequestContext carries all information about the current HTTP request through the detection pipeline. 承载当前 HTTP 请求在检测流水线中流转的所有信息。

func NewRequestContext

func NewRequestContext(r *http.Request, siteID string) (*RequestContext, error)

func NewRequestContextDeferredBody

func NewRequestContextDeferredBody(r *http.Request, siteID string, trustedCIDRs []string, maxBodyBytes int64) (*RequestContext, error)

NewRequestContextDeferredBody skips body I/O until EnsureBody (hot-path lazy-once).

func NewRequestContextDeferredBodyWithTrustedProxyPolicy

func NewRequestContextDeferredBodyWithTrustedProxyPolicy(r *http.Request, siteID string, policy *TrustedProxyPolicy, maxBodyBytes int64) (*RequestContext, error)

NewRequestContextDeferredBodyWithTrustedProxyPolicy uses a precompiled proxy policy and skips body I/O until EnsureBody.

func NewRequestContextWithLimits

func NewRequestContextWithLimits(r *http.Request, siteID string, trustedCIDRs []string, maxBodyBytes int64) (*RequestContext, error)

NewRequestContextWithLimits builds a context and eagerly reads the body.

func NewRequestContextWithTrustedProxies

func NewRequestContextWithTrustedProxies(r *http.Request, siteID string, trustedCIDRs []string) (*RequestContext, error)

func (*RequestContext) DetectionView added in v0.4.5

func (c *RequestContext) DetectionView(identity *http.Request) (*RequestContext, error)

DetectionView isolates one request identity while replaying this context's bounded immutable body snapshots. The identity's Body is never consumed.

func (*RequestContext) EnsureBody

func (c *RequestContext) EnsureBody() error

EnsureBody reads and rewinds the request body at most once. Callers without a request context still receive the independent upload idle bound.

func (*RequestContext) EnsureBodyContext

func (c *RequestContext) EnsureBodyContext(ctx context.Context) error

EnsureBodyContext materializes one shared body snapshot and waits for it with the caller's context. Only one reader worker is created per RequestContext; concurrent callers wait on the same completion channel. Snapshot publication is transactional: a read/decode error or cancellation never replaces the transport Body with bytes from an incomplete read.

type Severity

type Severity int

Severity represents the severity level of a detection. 检测的严重程度。

const (
	SeverityInfo     Severity = iota // 信息
	SeverityLow                      // 低
	SeverityMedium                   // 中
	SeverityHigh                     // 高
	SeverityCritical                 // 严重
)

func (Severity) String

func (s Severity) String() string

type TrustedProxyPolicy

type TrustedProxyPolicy = proxytrust.Policy

TrustedProxyPolicy is an immutable compiled client-IP trust policy.

func NewTrustedProxyPolicy

func NewTrustedProxyPolicy(trustedCIDRs []string, providerCIDRs map[string][]string) (*TrustedProxyPolicy, error)

NewTrustedProxyPolicy binds provider-specific headers to their own CIDRs.

Directories

Path Synopsis
Package decoder provides safe, bounded decoding helpers for the detection pipeline.
Package decoder provides safe, bounded decoding helpers for the detection pipeline.
Package response detects sensitive data in upstream responses.
Package response detects sensitive data in upstream responses.
Package rules implements configurable request matching for CheeseWAF.
Package rules implements configurable request matching for CheeseWAF.
Package semantic provides semantic functionality for CheeseWAF.
Package semantic provides semantic functionality for CheeseWAF.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL