// Copyright 2026 tamakyi. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package conf import ( "github.com/sirupsen/logrus" ) // 蜜罐相关配置的默认值。 // // 为什么要显式兜底:ini 的 MapTo 在「键缺失」或「值非法」时**不覆盖**目标字段, // 所以结构体的零值就是「未配置」的表现。而零值对这几个开关恰好是最危险的那个: // // - HoneypotAutoClean 零值 false → 未配置的站点自动清理是关的, // honeypot_hits 只增不减; // - HoneypotRetainDays 零值 0 → 保留期 0 天 = 永不清理; // - HoneypotMaxRows 零值 0 → 无行数上限。 // // 现场就踩过这个坑:配置写成了 honeypot_retention_days(多一个 t), // 键名不匹配被 ini 静默忽略,保留期成了 0,自动清理形同关闭。 const ( // DefaultHoneypotRetainDays 蜜罐记录默认保留天数。 DefaultHoneypotRetainDays = 30 // DefaultHoneypotMaxRows 蜜罐记录默认行数上限。 // 实测单行约 281 字节(含索引,常规 UA),20 万行约 53 MB。 DefaultHoneypotMaxRows = 200000 // DefaultHoneypotThreshold 蜜罐命中多少次即封禁。默认 1(一次即封): // 蜜罐路径与真实业务路由零交集,正常访客不可能命中。 DefaultHoneypotThreshold = 1 ) // sanitizeHoneypot 归一化蜜罐相关配置,修正「未配置」与「显式关闭」的歧义。 // // 语义约定(两个开关各管一件事,不再互相牵连): // // honeypot_auto_clean 是否启用后台自动清理。缺省 true(开)。 // honeypot_retain_days 保留多少天。缺省 30 天。 // // 也就是说:**要关闭自动清理请写 honeypot_auto_clean = false**, // 而不要靠把 retain_days 写成 0 —— 保留 0 天意味着「记录一进来就删」, // 既不是任何人的真实意图,也会让「自动清理到底开没开」变得无法判断。 // // 显式写 honeypot_max_rows = 0 仍表示「不设行数上限」(这是明确的逃生口), // 但会告警提醒:没有时间闸也没有数量闸的表只增不减。 func sanitizeHoneypot() { sec := File.Section("security") hasRetain := sec.HasKey("honeypot_retain_days") hasMaxRows := sec.HasKey("honeypot_max_rows") // 保留期:未配置或显式 <= 0 → 回退默认。 // 显式 0 的语义是「立刻删除」,与「不自动清理」混淆,判为误配。 if !hasRetain { Security.HoneypotRetainDays = DefaultHoneypotRetainDays } else if Security.HoneypotRetainDays <= 0 { logrus.WithField("default", DefaultHoneypotRetainDays). Warn("honeypot_retain_days <= 0 已被忽略,改用默认值(如需关闭自动清理请设 honeypot_auto_clean = false)") Security.HoneypotRetainDays = DefaultHoneypotRetainDays } // 行数上限:未配置 → 默认;显式 0 → 不设上限(逃生口,但告警)。 if !hasMaxRows { Security.HoneypotMaxRows = DefaultHoneypotMaxRows } else if Security.HoneypotMaxRows <= 0 { logrus.Warn("honeypot_max_rows = 0 表示不设行数上限:蜜罐表将只增不减,请确认这是有意为之") } // 自动清理:缺省开启。 // 判据用 HasKey 而不是值 —— 因为 ini 对 bool 的解析是「有键才赋值」, // 缺键时零值 false 会让「未配置」与「显式关闭」无法区分。 // 显式 false 是合法的关闭意图,予以尊重(与 retain_days 的处理不同)。 if !sec.HasKey("honeypot_auto_clean") { Security.HoneypotAutoClean = true } // 封禁阈值:缺省 1。 if !sec.HasKey("honeypot_threshold") { Security.HoneypotThreshold = DefaultHoneypotThreshold } }