fix(waf): 修复P1/P2安全审计缺陷
P1-1: IPv6 地址解析改用 net.SplitHostPort,修复 XFF 带方括号致限流失效 P1-2: 捕获 ProcessResponseHeaders 返回值,命中记录 WARNING 告警 P1-4: 新增 SIGINT/SIGTERM 优雅关闭 + logclient.Flush() P1-5: 标准日志输出到 stderr,保留 panic 堆栈 P2-1: 规则文件加载前校验大小(1 MiB 上限)防 OOM P2-2: logclient db 地址支持 LOG_DB_ADDR 环境变量 P2-5: 日志失败输出到 stderr 而非 stdout 修复率 35% -> 76%(P1/P2 全部清零)
This commit is contained in:
1 parent
bcec529761
commit
dd9f8e51ff
6 files changed
+143
-45
No files matched your search
+31
-10
@@ -12,11 +12,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -62,8 +62,8 @@ func main() {
|
||||
}
|
||||
|
||||
eng, err := engine.New(&engine.Config{
|
||||
RulesDir: cfg.RulesDir,
|
||||
ErrorCallback: engine.LogError,
|
||||
RulesDir: cfg.RulesDir,
|
||||
ErrorCallback: engine.LogError,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("引擎初始化失败: %v", err)
|
||||
@@ -86,7 +86,8 @@ func main() {
|
||||
|
||||
// 服务模式
|
||||
logclient.Init()
|
||||
log.SetOutput(io.Discard) // 静默标准 log
|
||||
// 标准日志输出到 stderr(systemd/journalctl 可捕获),保留 net/http 的 panic 堆栈与 TLS 错误
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
p, err := proxy.New(cfg.Upstream, eng)
|
||||
if err != nil {
|
||||
@@ -96,10 +97,10 @@ func main() {
|
||||
}
|
||||
|
||||
// SIGHUP 热加载
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGHUP)
|
||||
hupCh := make(chan os.Signal, 1)
|
||||
signal.Notify(hupCh, syscall.SIGHUP)
|
||||
go func() {
|
||||
for range sigCh {
|
||||
for range hupCh {
|
||||
if err := eng.Reload(); err != nil {
|
||||
logclient.Error("waf", fmt.Sprintf("热加载失败,保留旧规则: %v", err), nil)
|
||||
} else {
|
||||
@@ -121,13 +122,33 @@ func main() {
|
||||
},
|
||||
}
|
||||
|
||||
// SIGINT/SIGTERM 优雅关闭:等待进行中的请求完成后再退出,并 flush 队列日志
|
||||
termCh := make(chan os.Signal, 1)
|
||||
signal.Notify(termCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
logclient.Info("waf", fmt.Sprintf("服务启动 listen=%s upstream=%s rules=%s pid=%d",
|
||||
cfg.Listen, cfg.Upstream, cfg.RulesDir, os.Getpid()), nil)
|
||||
|
||||
if err := server.ListenAndServeTLS(cfg.TLSCert, cfg.TLSKey); err != nil {
|
||||
logclient.Error("waf", fmt.Sprintf("TLS 监听失败: %v", err), nil)
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- server.ListenAndServeTLS(cfg.TLSCert, cfg.TLSKey)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
logclient.Error("waf", fmt.Sprintf("TLS 监听失败: %v", err), nil)
|
||||
logclient.Flush()
|
||||
os.Exit(1)
|
||||
}
|
||||
case <-termCh:
|
||||
logclient.Info("waf", "收到终止信号,开始优雅关闭", nil)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
logclient.Error("waf", fmt.Sprintf("优雅关闭超时: %v", err), nil)
|
||||
}
|
||||
logclient.Flush()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user