miguan v1
This commit is contained in:
+38
-3
@@ -26,11 +26,13 @@ import (
|
||||
"github.com/tamakyi/TamaBox/internal/captcha"
|
||||
"github.com/tamakyi/TamaBox/internal/conf"
|
||||
"github.com/tamakyi/TamaBox/internal/context"
|
||||
"github.com/tamakyi/TamaBox/internal/db"
|
||||
"github.com/tamakyi/TamaBox/internal/form"
|
||||
"github.com/tamakyi/TamaBox/internal/i18n"
|
||||
"github.com/tamakyi/TamaBox/internal/mail"
|
||||
"github.com/tamakyi/TamaBox/internal/route/chat" // 私聊路由
|
||||
"github.com/tamakyi/TamaBox/internal/security/autoban"
|
||||
"github.com/tamakyi/TamaBox/internal/security/honeypot"
|
||||
"github.com/tamakyi/TamaBox/internal/security/ipinfo"
|
||||
"github.com/tamakyi/TamaBox/internal/shared"
|
||||
templatepkg "github.com/tamakyi/TamaBox/internal/template"
|
||||
@@ -96,6 +98,19 @@ func New() *flamego.Flame {
|
||||
},
|
||||
})
|
||||
|
||||
// 蜜罐(虚假后台登录界面):默认关闭,需在 [security] 段显式 enable_honeypot = true。
|
||||
// 命中即返回假登录页 + 记录破解凭据 + 复用上面的 autoban 封禁/告警链路。
|
||||
hp := honeypot.New(honeypot.Options{
|
||||
Enabled: conf.Security.EnableHoneypot,
|
||||
ExtraPaths: honeypotExtraPaths(conf.Security.HoneypotPaths),
|
||||
})
|
||||
hph := newHoneypotHandler(hp, ab, db.Honeypots)
|
||||
// 蜜罐告警:只有真的提交了凭据才发(纯路径探测没有取证价值),且每个 IP 只发一次。
|
||||
// 收件人复用 security_alert_email,不新增配置项。
|
||||
hph.sendAlert = func(a mail.HoneypotAlert) error {
|
||||
return mail.SendHoneypotAlertMail(a)
|
||||
}
|
||||
|
||||
templateFS, err := template.EmbedFS(templates.FS, ".", []string{".html"})
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("Failed to embed templates file system")
|
||||
@@ -148,7 +163,7 @@ func New() *flamego.Flame {
|
||||
|
||||
f.Use(securityHeaders())
|
||||
f.Use(ipBlacklistMiddleware())
|
||||
f.Use(autobanMiddleware(ab))
|
||||
f.Use(autobanMiddleware(ab, hp))
|
||||
// 全局请求体上限:必须在任何会读取 body 的中间件(尤其 Contexter 内的 CSRF 校验)
|
||||
// 之前执行,否则超大 multipart 会在 Bind 的路由级限制生效前落盘临时文件耗尽磁盘。
|
||||
f.Use(requestBodyLimitMiddleware())
|
||||
@@ -430,8 +445,28 @@ func New() *flamego.Flame {
|
||||
context.Contexter(),
|
||||
)
|
||||
f.NotFound(func(ctx flamego.Context) {
|
||||
// 真正的 404 探测在此记录(不把业务 302→/ 误判为扫描)。flamego 的 NotFound 会先
|
||||
// 写 404 状态再 Redirect,故须在 Redirect 前记录。
|
||||
// ── 蜜罐分流(优先)───────────────────────────────────────────────
|
||||
// 命中诱饵路径(/wp-admin、/.ssh、/.env 等后台探测特征)时,返回一个
|
||||
// 仿 WordPress 的假登录页,并把攻击者提交的凭据记录入库。
|
||||
//
|
||||
// 为什么挂在 NotFound 而不是全局中间件:NotFound 只在「路由表完全落空」
|
||||
// 时触发,因此与 /login、/register、/_/{domain}、/user/**、/api/v1/** 等
|
||||
// 真实业务路由天然零交集,不会劫持正常用户;且它位于全局 f.Use 链之后,
|
||||
// requestBodyLimitMiddleware 已对 body 施加上限,解析 POST body 安全。
|
||||
// 组级中间件(含 CSRF)只挂在具体路由上,不作用于 NotFound,故表单可解析。
|
||||
//
|
||||
// 短路:flamego 的 context.run() 在 ResponseWriter().Written() 为真时即
|
||||
// return,故此处写完响应且不调用 ctx.Next() 即可安全终止整条链路。
|
||||
if hp != nil && hp.Match(ctx.Request().URL.Path) {
|
||||
hph.Serve(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
// 真正的 404 探测在此记录(不把业务 302→/ 误判为扫描)。
|
||||
// ⚠️ 更正:flamego 的 NotFound 处理器并不会自动写 404 状态码 ——
|
||||
// ResponseWriter.Write() 在未显式 WriteHeader 时写的是 200,
|
||||
// ctx.Redirect("/") 写的是 302 + Location: /。这里保持原有 302→/ 行为
|
||||
// (对扫描器而言,302 到首页同样表示「此路径不存在」)。
|
||||
// 键必须与 autobanMiddleware 的 IsBanned/Record 一致(同样经 LimitKey 聚合),
|
||||
// 否则计数落在另一个键上,封禁永不生效。
|
||||
// ⚠️ 计数受 ban_track_notfound 控制,默认关闭;Record 内部会忽略未开启的
|
||||
|
||||
Reference in New Issue
Block a user