🔒️ security(server): 业务接口保护开关与存活探针

- access_key 改用 subtle.ConstantTimeCompare 常量时间比较,防时序攻击
- 新增 server.protect_all 配置:开启后业务接口(/search、/content 等)也要求访问密钥
- 代理路由(/audio/proxy/、/manga/image/)不参与保护,其 URL 由服务端生成不含 key
- 新增 /healthz 存活探针(不校验密钥,供容器/反代使用)
- openapi.yaml 补 /healthz 定义,Unauthorized 描述说明 protect_all 行为
- 新增 3 个测试:保护开关放行、healthz、错误响应行为
This commit is contained in:
chenxin committed 2026-09-29 22:51:39 +08:00
1 parent d1774a3902
commit 24c7e4b6fd
5 files changed
+78 -26

No files matched your search

+20
View File
@@ -2,6 +2,7 @@ package handlers
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
@@ -40,3 +41,22 @@ func TestHandleDetailMissingParam(t *testing.T) {
t.Errorf("缺参应返回 400, got %d, body: %s", w.Code, w.Body.String())
}
}
// TestOptionalAccessKeyDisabled protect_all 未启用(或配置未加载)时直接放行
func TestOptionalAccessKeyDisabled(t *testing.T) {
called := false
h := OptionalAccessKey(func(w http.ResponseWriter, r *http.Request) { called = true })
h(httptest.NewRecorder(), httptest.NewRequest("GET", "/search?query=x", nil))
if !called {
t.Error("protect_all 未启用时应直接放行")
}
}
// TestHandleHealth 存活探针返回 200 ok
func TestHandleHealth(t *testing.T) {
w := httptest.NewRecorder()
HandleHealth(w, httptest.NewRequest("GET", "/healthz", nil))
if w.Code != 200 || w.Body.String() != "ok" {
t.Errorf("应返回 200 ok, got %d %q", w.Code, w.Body.String())
}
}