feat(config): 增强配置验证功能,添加多项验证函数

新增 validateLogging、validateRewrite、validateSecurityHeaders 验证函数,
完善限流算法、滑动窗口模式、一致性哈希键格式验证,
在 YAML 默认配置中添加 trusted_proxies 字段说明。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
xfy 2026-04-07 13:15:27 +08:00
parent 3cc2dc7625
commit 20016ebb59
3 changed files with 185 additions and 1 deletions

View File

@ -439,5 +439,10 @@ func Validate(cfg *Config) error {
}
}
// 验证日志配置
if err := validateLogging(&cfg.Logging); err != nil {
return err
}
return nil
}

View File

@ -250,6 +250,7 @@ func GenerateConfigYAML(cfg *Config) ([]byte, error) {
buf.WriteString(" allow: [] # 允许的 IP/CIDR 列表\n")
buf.WriteString(" deny: [] # 拒绝的 IP/CIDR 列表\n")
fmt.Fprintf(&buf, " default: \"%s\" # 默认动作(有效值: allow, deny\n", cfg.Server.Security.Access.Default)
buf.WriteString(" trusted_proxies: [] # 可信代理 CIDR 列表,用于 X-Forwarded-For 解析\n")
buf.WriteString("\n")
buf.WriteString(" # 速率限制\n")
buf.WriteString(" rate_limit:\n")

View File

@ -66,6 +66,13 @@ func validateServer(s *ServerConfig, isDefault bool) error {
}
}
// 验证重写规则
for i := range s.Rewrite {
if err := validateRewrite(&s.Rewrite[i]); err != nil {
return fmt.Errorf("rewrite[%d]: %w", i, err)
}
}
// 验证 SSL 配置
if err := validateSSL(&s.SSL); err != nil {
return fmt.Errorf("ssl: %w", err)
@ -145,6 +152,21 @@ func validateProxy(p *ProxyConfig) error {
return fmt.Errorf("无效的负载均衡算法:%s", p.LoadBalance)
}
// 验证一致性哈希键格式
if p.HashKey != "" {
validHashKeys := []string{"ip", "uri"}
valid := false
for _, k := range validHashKeys {
if p.HashKey == k || strings.HasPrefix(p.HashKey, "header:") {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的 hash_key: %s仅支持 ip, uri 或 header:X-Name 格式)", p.HashKey)
}
}
return nil
}
@ -198,7 +220,7 @@ func validateSSL(s *SSLConfig) error {
// validateSecurity 验证安全配置。
//
// 验证访问控制、认证和速率限制配置的有效性。
// 验证访问控制、认证、速率限制和安全头部的有效性。
//
// 参数:
// - s: 安全配置对象
@ -221,6 +243,11 @@ func validateSecurity(s *SecurityConfig) error {
return fmt.Errorf("rate_limit: %w", err)
}
// 验证安全头部配置
if err := validateSecurityHeaders(&s.Headers); err != nil {
return fmt.Errorf("headers: %w", err)
}
return nil
}
@ -368,6 +395,32 @@ func validateRateLimit(r *RateLimitConfig) error {
return fmt.Errorf("无效的 key 来源: %s仅支持 ip 或 header", r.Key)
}
// 验证限流算法
validAlgorithms := []string{"", "token_bucket", "sliding_window"}
valid = false
for _, alg := range validAlgorithms {
if r.Algorithm == alg {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的限流算法: %s仅支持 token_bucket 或 sliding_window", r.Algorithm)
}
// 验证滑动窗口模式
validModes := []string{"", "approximate", "precise"}
valid = false
for _, mode := range validModes {
if r.SlidingWindowMode == mode {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的滑动窗口模式: %s仅支持 approximate 或 precise", r.SlidingWindowMode)
}
return nil
}
@ -417,6 +470,131 @@ func validateCompression(c *CompressionConfig) error {
return nil
}
// validateRewrite 验证 URL 重写规则。
//
// 检查重写模式、替换目标和标志的有效性。
//
// 参数:
// - r: 重写规则配置对象
//
// 返回值:
// - error: 验证失败时返回错误信息,成功返回 nil
//
// 验证规则:
// - pattern 必填
// - flag 仅允许 last, redirect, permanent, break
func validateRewrite(r *RewriteRule) error {
// 模式必填
if r.Pattern == "" {
return errors.New("pattern 必填")
}
// 验证标志
validFlags := []string{"", "last", "redirect", "permanent", "break"}
valid := false
for _, f := range validFlags {
if r.Flag == f {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的 flag: %s仅支持 last, redirect, permanent, break", r.Flag)
}
return nil
}
// validateLogging 验证日志配置。
//
// 检查日志格式和级别的有效性。
//
// 参数:
// - l: 日志配置对象
//
// 返回值:
// - error: 验证失败时返回错误信息,成功返回 nil
//
// 验证规则:
// - format 仅允许 text 或 json
// - level 仅允许 debug, info, warn, error
func validateLogging(l *LoggingConfig) error {
// 验证日志格式
validFormats := []string{"", "text", "json"}
valid := false
for _, f := range validFormats {
if l.Format == f {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的日志格式: %s仅支持 text 或 json", l.Format)
}
// 验证错误日志级别
validLevels := []string{"", "debug", "info", "warn", "error"}
valid = false
for _, lvl := range validLevels {
if l.Error.Level == lvl {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的日志级别: %s仅支持 debug, info, warn, error", l.Error.Level)
}
return nil
}
// validateSecurityHeaders 验证安全头部配置。
//
// 检查各安全头部值的有效性。
//
// 参数:
// - h: 安全头部配置对象
//
// 返回值:
// - error: 验证失败时返回错误信息,成功返回 nil
//
// 验证规则:
// - x_frame_options 仅允许 DENY, SAMEORIGIN 或空
// - referrer_policy 仅允许标准 RFC 值
func validateSecurityHeaders(h *SecurityHeaders) error {
// 验证 X-Frame-Options
validFrameOptions := []string{"", "DENY", "SAMEORIGIN"}
valid := false
for _, opt := range validFrameOptions {
if h.XFrameOptions == opt {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的 x_frame_options: %s仅支持 DENY, SAMEORIGIN 或空)", h.XFrameOptions)
}
// 验证 Referrer-Policy
validReferrerPolicies := []string{
"", "no-referrer", "no-referrer-when-downgrade", "origin",
"origin-when-cross-origin", "same-origin", "strict-origin",
"strict-origin-when-cross-origin", "unsafe-url",
}
valid = false
for _, policy := range validReferrerPolicies {
if h.ReferrerPolicy == policy {
valid = true
break
}
}
if !valid {
return fmt.Errorf("无效的 referrer_policy: %s", h.ReferrerPolicy)
}
return nil
}
// validateStream 验证 Stream 代理配置。
//
// 检查监听地址、协议类型和上游配置的有效性。