安全加固:Web 登录防爆破(IP+用户名双维度限速 5次/分钟锁10分钟,未知用户名 dummy bcrypt 防枚举),瓦片代理 SSRF 加固(DialContext 拒绝内网/链路本地/CGNAT/ULA 与重定向限制,Content-Type image 白名单+nosniff),/api/discard-details 公开去敏(新增 admin 全字段端点),公开地图源接口外部 URL/key 一律代理化,install.sh 随机管理员密码+非回环默认口令拒绝启动,后端 v1.4.0

This commit is contained in:
2026-08-20 17:00:41 +08:00
parent fe0cf036cf
commit f21e8337af
13 changed files with 658 additions and 48 deletions
+53
View File
@@ -0,0 +1,53 @@
package main
import (
"testing"
configpkg "meshtastic_mqtt_server/internal/config"
)
func TestIsLoopbackHost(t *testing.T) {
for _, in := range []string{"localhost", "127.0.0.1", "::1", "LOCALHOST"} {
if !isLoopbackHost(in) {
t.Errorf("%q should be loopback", in)
}
}
for _, in := range []string{"0.0.0.0", "", "192.168.1.5", " ", "meshmap.lmve.net"} {
if isLoopbackHost(in) {
t.Errorf("%q should not be loopback", in)
}
}
}
func TestGuardDefaultAdminPassword(t *testing.T) { webEnabled := func(host, password string, portEnabled bool) *configpkg.Config {
return &configpkg.Config{
Web: configpkg.WebConfig{
Enabled: true,
PortEnabled: portEnabled,
Host: host,
Admin: configpkg.WebAdminConfig{Username: "admin", Password: password},
},
}
}
cases := []struct {
name string
cfg *configpkg.Config
reject bool
}{
{"公网+默认口令", webEnabled("0.0.0.0", "admin", true), true},
{"公网+自定义口令", webEnabled("0.0.0.0", "s3cret!", true), false},
{"回环+默认口令", webEnabled("127.0.0.1", "admin", true), false},
{"空口令", webEnabled("0.0.0.0", "", true), true},
{"仅socket", webEnabled("0.0.0.0", "admin", false), false},
}
for _, tc := range cases {
err := guardDefaultAdminPassword(tc.cfg)
if tc.reject && err == nil {
t.Errorf("%s: expected rejection", tc.name)
}
if !tc.reject && err != nil {
t.Errorf("%s: unexpected rejection: %v", tc.name, err)
}
}
}