package panel import ( "net/http" "net/http/httptest" "strings" "testing" ) func newTestPanel() *Panel { // 启用鉴权:未带 key 的请求一律 401,不进入依赖 Pool/Upstream 的 handler。 return New(Config{Version: "test", APIKey: "test-key"}) } // 面板安全响应头必须覆盖:页面、静态脚本、鉴权失败响应。 func TestSecurityHeadersOnAllPanelResponses(t *testing.T) { p := newTestPanel() paths := []struct{ method, path string }{ {"GET", "/panel/"}, {"GET", "/panel/app.js"}, {"GET", "/panel/api/overview"}, // 401(未提供 key) {"POST", "/panel/api/config"}, // 401 {"GET", "/panel/api/nonexistent"}, } for _, c := range paths { rec := httptest.NewRecorder() p.ServeHTTP(rec, httptest.NewRequest(c.method, c.path, nil)) h := rec.Header() if got := h.Get("Content-Security-Policy"); got == "" { t.Errorf("%s %s: missing CSP", c.method, c.path) } if h.Get("X-Content-Type-Options") != "nosniff" { t.Errorf("%s %s: X-Content-Type-Options=%q", c.method, c.path, h.Get("X-Content-Type-Options")) } if h.Get("X-Frame-Options") != "DENY" { t.Errorf("%s %s: X-Frame-Options=%q", c.method, c.path, h.Get("X-Frame-Options")) } if h.Get("Referrer-Policy") != "no-referrer" { t.Errorf("%s %s: Referrer-Policy=%q", c.method, c.path, h.Get("Referrer-Policy")) } } } // CSP 必须禁止内联脚本与 iframe 嵌套(严格策略的核心约束)。 func TestCSPDisallowsInlineScriptAndFraming(t *testing.T) { p := newTestPanel() rec := httptest.NewRecorder() p.ServeHTTP(rec, httptest.NewRequest("GET", "/panel/", nil)) csp := rec.Header().Get("Content-Security-Policy") for _, must := range []string{ "script-src 'self'", "frame-ancestors 'none'", "base-uri 'none'", "default-src 'none'", } { if !strings.Contains(csp, must) { t.Errorf("CSP missing %q; got: %s", must, csp) } } if strings.Contains(csp, "script-src 'self' 'unsafe-inline'") || strings.Contains(csp, "script-src 'unsafe-inline'") { t.Errorf("CSP must not allow unsafe-inline scripts; got: %s", csp) } } // 页面必须引用外部脚本(内联脚本会被上面的 CSP 拦掉,页面将完全不可用)。 func TestIndexReferencesExternalScript(t *testing.T) { p := newTestPanel() rec := httptest.NewRecorder() p.ServeHTTP(rec, httptest.NewRequest("GET", "/panel/", nil)) body := rec.Body.String() if !strings.Contains(body, ``) { t.Error("index.html must load app.js externally (inline script is blocked by CSP)") } // 反例保护:出现内联 内容块即为回归 if strings.Contains(body, "