mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-01 15:02:58 +08:00
fix: 安全初始化 Gin 可信代理
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -47,18 +47,7 @@ func ProvideRouter(
|
||||
|
||||
r := gin.New()
|
||||
r.Use(middleware2.Recovery())
|
||||
if len(cfg.Server.TrustedProxies) > 0 {
|
||||
if err := r.SetTrustedProxies(cfg.Server.TrustedProxies); err != nil {
|
||||
log.Printf("Failed to set trusted proxies: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err := r.SetTrustedProxies(nil); err != nil {
|
||||
log.Printf("Failed to disable trusted proxies: %v", err)
|
||||
}
|
||||
if cfg.Server.Mode == "release" {
|
||||
log.Printf("Warning: server.trusted_proxies is empty in release mode; client IP trust chain is disabled")
|
||||
}
|
||||
}
|
||||
configureTrustedProxies(r, cfg.Server)
|
||||
|
||||
// Wire up websearch Manager builder so it initializes on startup and rebuilds on config save.
|
||||
settingService.SetWebSearchManagerBuilder(context.Background(), func(cfg *service.WebSearchEmulationConfig, proxyURLs map[int64]string) {
|
||||
@@ -99,6 +88,25 @@ func ProvideRouter(
|
||||
return SetupRouter(r, handlers, jwtAuth, adminAuth, apiKeyAuth, auditLog, stepUpAuth, apiKeyService, subscriptionService, opsService, settingService, cfg, redisClient)
|
||||
}
|
||||
|
||||
func configureTrustedProxies(r *gin.Engine, cfg config.ServerConfig) {
|
||||
if cfg.TrustedProxiesConfigured {
|
||||
if err := r.SetTrustedProxies(cfg.TrustedProxies); err != nil {
|
||||
log.Printf("Failed to set trusted proxies: %v", err)
|
||||
_ = r.SetTrustedProxies(nil)
|
||||
}
|
||||
if len(cfg.TrustedProxies) == 0 && cfg.Mode == "release" {
|
||||
log.Printf("Warning: server.trusted_proxies is explicitly empty; forwarded client IP trust is disabled")
|
||||
}
|
||||
} else {
|
||||
if err := r.SetTrustedProxies(nil); err != nil {
|
||||
log.Printf("Failed to disable trusted proxies: %v", err)
|
||||
}
|
||||
if cfg.Mode == "release" {
|
||||
log.Printf("Warning: server.trusted_proxies is not configured; disabling the forwarded-IP compatibility switch will use direct peer addresses only")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProvideHTTPServer 提供 HTTP 服务器
|
||||
func ProvideHTTPServer(cfg *config.Config, router *gin.Engine) *http.Server {
|
||||
httpHandler := http.Handler(router)
|
||||
|
||||
@@ -55,6 +55,56 @@ func TestProvideHTTPServerEnablesBoundedH2C(t *testing.T) {
|
||||
require.True(t, srv.Protocols.HTTP1())
|
||||
}
|
||||
|
||||
func TestConfigureTrustedProxies(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg config.ServerConfig
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "configured proxy resolves forwarded client",
|
||||
cfg: config.ServerConfig{
|
||||
TrustedProxies: []string{"9.9.9.9/32"},
|
||||
TrustedProxiesConfigured: true,
|
||||
},
|
||||
want: "1.2.3.4",
|
||||
},
|
||||
{
|
||||
name: "explicit empty list ignores forwarded client",
|
||||
cfg: config.ServerConfig{
|
||||
TrustedProxiesConfigured: true,
|
||||
},
|
||||
want: "9.9.9.9",
|
||||
},
|
||||
{
|
||||
name: "invalid proxy list fails closed",
|
||||
cfg: config.ServerConfig{
|
||||
TrustedProxies: []string{"not-a-cidr"},
|
||||
TrustedProxiesConfigured: true,
|
||||
},
|
||||
want: "9.9.9.9",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
r := gin.New()
|
||||
configureTrustedProxies(r, tc.cfg)
|
||||
r.GET("/t", func(c *gin.Context) { c.String(http.StatusOK, c.ClientIP()) })
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/t", nil)
|
||||
req.RemoteAddr = "9.9.9.9:12345"
|
||||
req.Header.Set("X-Forwarded-For", "1.2.3.4")
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
require.Equal(t, tc.want, w.Body.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPServerRejectsOversizedHTTP1Header(t *testing.T) {
|
||||
r := gin.New()
|
||||
r.GET("/", func(c *gin.Context) { c.Status(http.StatusOK) })
|
||||
|
||||
Reference in New Issue
Block a user