mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-09-03 07:24:52 +08:00
Managed WAF rulesets read a path in a query string as a directory-traversal
attempt and block the request at the edge. Measured against Cloudflare:
GET /api/nginx_log/preflight -> 403 application/json (our auth)
GET /api/nginx_log/preflight?log_path=%2Fvar%2Flog%2Fnginx%2Faccess.log
-> 403 text/html (Cloudflare)
Same endpoint, same credentials; only the path-shaped value differs. Note the
blocked request was already percent-encoded — WAFs normalise that before
matching, so escaping harder does not help. This hits any operator behind a
WAF, so it belongs in the product rather than in a per-zone exception.
Send such values base64url-encoded behind a `b64_` prefix instead. The output
alphabet is [A-Za-z0-9_-], leaving no slash, no dot and nothing for a signature
to match.
Seven parameters were affected, two worse than the one that was reported:
`filepath` on GET /api/config_histories is always a fully absolute path, and
`path` on GET /api/nginx_logs is a search box whose contents the operator types
straight into the URL.
Two constraints shaped the implementation:
Decoding happens in each handler, strictly BEFORE path validation. The other
order would let `../../../etc/passwd` hide inside the encoding and slip past
IsUnderDirectory and IsValidLogPath. Tests in internal/config and
internal/nginx_log/utils pin the ordering down so it cannot be reversed later.
It cannot live in middleware either: AuthRequired reads c.Query("x_node_id"),
which freezes gin's query cache before any later middleware could rewrite it.
The frontend does it in the one existing request interceptor rather than at
call sites. That is not merely tidier — two of the seven parameters are
generated by useCurdApi and have no call site to patch. The transform is an
allowlist keyed on URL, because GET /api/settings/protected also takes `path`
and its value is a settings key like `app.jwt_secret` that must arrive intact.
Raw values keep working: a value is treated as encoded only if it starts with
`b64_`, decodes as base64url, and yields valid NUL-free UTF-8. Absolute paths
fail the first clause, relative config paths contain characters outside the
alphabet and fail the second. A bare "try to decode, else treat as raw"
heuristic was rejected — `defaultsite` is itself valid base64url and would
silently decode to binary.
Left alone deliberately: paths already travelling in POST bodies, the SPA's own
routes (hash history keeps them out of the request line), and
/api/settings/protected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nginx Log Performance Utils
This package provides performance optimization utilities for the nginx-ui log processing system.
Overview
This package consolidates performance optimization code that was previously duplicated across indexer, parser, and searcher packages. The utilities focus on reducing memory allocations, improving concurrency, and providing efficient data structures.
Components
StringPool
- Provides efficient string reuse and interning to reduce memory allocations
- Thread-safe string interning with configurable limits
- Byte buffer pooling for temporary string operations
pool := utils.NewStringPool()
buf := pool.Get() // Get a reusable byte buffer
str := pool.Intern("text") // Intern strings to reduce duplicates
pool.Put(buf) // Return buffer to pool
MemoryPool
- Multi-size buffer pooling for different allocation needs
- Automatic size selection based on requirements
- Prevents memory fragmentation and reduces GC pressure
pool := utils.NewMemoryPool()
buf := pool.Get(1024) // Get buffer with at least 1024 bytes capacity
pool.Put(buf) // Return buffer to appropriate pool
WorkerPool
- Optimized goroutine management with bounded concurrency
- Queue-based work distribution
- Graceful shutdown support
pool := utils.NewWorkerPool(10, 100) // 10 workers, 100 queue size
pool.Submit(func() { /* work */ }) // Submit work
pool.Close() // Shutdown gracefully
BatchProcessor
- Efficient batch collection and processing
- Thread-safe operations with configurable capacity
- Automatic batch reset after retrieval
bp := utils.NewBatchProcessor(100)
bp.Add(item) // Add items to batch
batch := bp.GetBatch() // Get and reset batch
MemoryOptimizer
- Memory usage monitoring and GC optimization
- Configurable thresholds and intervals
- Detailed memory statistics
mo := utils.NewMemoryOptimizer(512 * 1024 * 1024) // 512MB threshold
mo.CheckMemoryUsage() // Trigger GC if needed
stats := mo.GetMemoryStats() // Get memory statistics
PerformanceMetrics
- Thread-safe performance tracking
- Operation counting, timing, and error rates
- Cache hit/miss ratio tracking
pm := utils.NewPerformanceMetrics()
pm.RecordOperation(itemCount, duration, success)
pm.RecordCacheHit()
metrics := pm.GetMetrics() // Get performance snapshot
Unsafe Conversions
Zero-allocation string/byte conversions for performance-critical code:
BytesToStringUnsafe([]byte) stringStringToBytesUnsafe(string) []byteAppendInt([]byte, int) []byte
⚠️ Warning: These functions use unsafe operations and should be used carefully.
Testing
The package includes comprehensive tests covering:
- Basic functionality for all components
- Concurrent access patterns
- Performance benchmarks
- Edge cases and error conditions
Run tests with:
go test ./internal/nginx_log/utils/... -v
Run benchmarks with:
go test ./internal/nginx_log/utils/... -bench=.
Migration Notes
This package replaces the previous performance_optimizations.go files in:
internal/nginx_log/indexer/performance_optimizations.go(removed)internal/nginx_log/parser/performance_optimizations.go(removed)internal/nginx_log/searcher/performance_optimizations.go(removed)
The consolidated implementation provides:
- Better code reuse and maintenance
- Consistent performance optimizations across packages
- Comprehensive test coverage
- Improved documentation
Usage Guidelines
- Use
StringPoolfor frequent string operations and temporary buffers - Use
MemoryPoolfor variable-size buffer allocations - Use
WorkerPoolfor CPU-bound tasks requiring concurrency control - Use
BatchProcessorfor collecting items before bulk operations - Use
MemoryOptimizerin long-running processes to manage memory - Use
PerformanceMetricsto track and monitor system performance - Use unsafe conversions sparingly and only in performance-critical sections