fix: protect appsrv default handlers (#22341)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2025-03-26 17:51:54 +08:00
committed by GitHub
parent 09b079795f
commit 11bff68aa1
7 changed files with 78 additions and 12 deletions
+1
View File
@@ -118,6 +118,7 @@ var (
"enable_cloud_shell",
"platform_names",
"enable_change_owner_auto_rename",
"default_handlers_whitelist_user_agents",
},
}
+6 -6
View File
@@ -463,12 +463,12 @@ func (app *Application) AddDefaultHandler(method string, prefix string, handler
}
func (app *Application) addDefaultHandlers() {
app.AddDefaultHandler("GET", "/version", VersionHandler, "version")
app.AddDefaultHandler("GET", "/stats", StatisticHandler, "stats")
app.AddDefaultHandler("POST", "/ping", PingHandler, "ping")
app.AddDefaultHandler("GET", "/ping", PingHandler, "ping")
app.AddDefaultHandler("GET", "/worker_stats", WorkerStatsHandler, "worker_stats")
app.AddDefaultHandler("GET", "/process_stats", ProcessStatsHandler, "process_stats")
app.AddDefaultHandler("GET", "/version", WhitelistFilter(VersionHandler), "version")
app.AddDefaultHandler("GET", "/stats", WhitelistFilter(StatisticHandler), "stats")
app.AddDefaultHandler("POST", "/ping", WhitelistFilter(PingHandler), "ping")
app.AddDefaultHandler("GET", "/ping", WhitelistFilter(PingHandler), "ping")
app.AddDefaultHandler("GET", "/worker_stats", WhitelistFilter(WorkerStatsHandler), "worker_stats")
app.AddDefaultHandler("GET", "/process_stats", WhitelistFilter(ProcessStatsHandler), "process_stats")
}
func timeoutHandle(h http.Handler) http.HandlerFunc {
+6 -6
View File
@@ -60,12 +60,12 @@ func addPProfHandler(prefix string, app *Application) {
} else {
prefix = pp
}
app.AddHandler("GET", fmt.Sprintf("%s/", prefix), profIndex).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/cmdline", prefix), profCmdline).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/profile", prefix), profProfile).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/symbol", prefix), profSymbol).SetProcessNoTimeout()
app.AddHandler("POST", fmt.Sprintf("%s/symbol", prefix), profSymbol).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/trace", prefix), profTrace).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/", prefix), WhitelistFilter(profIndex)).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/cmdline", prefix), WhitelistFilter(profCmdline)).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/profile", prefix), WhitelistFilter(profProfile)).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/symbol", prefix), WhitelistFilter(profSymbol)).SetProcessNoTimeout()
app.AddHandler("POST", fmt.Sprintf("%s/symbol", prefix), WhitelistFilter(profSymbol)).SetProcessNoTimeout()
app.AddHandler("GET", fmt.Sprintf("%s/trace", prefix), WhitelistFilter(profTrace)).SetProcessNoTimeout()
}
func profIndex(_ context.Context, w http.ResponseWriter, r *http.Request) {
+58
View File
@@ -0,0 +1,58 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package appsrv
import (
"context"
"net/http"
"strings"
"yunion.io/x/log"
"yunion.io/x/pkg/util/httputils"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/httperrors"
)
var (
whitelisUserAgents []string
)
const kubeProbeUserAgent = "kube-probe"
func SetDefaultHandlersWhitelistUserAgents(userAgents []string) {
for _, userAgent := range userAgents {
whitelisUserAgents = append(whitelisUserAgents, strings.ToLower(userAgent))
}
if !utils.IsInArray(httputils.USER_AGENT, whitelisUserAgents) {
whitelisUserAgents = append(whitelisUserAgents, httputils.USER_AGENT)
}
if !utils.IsInArray(kubeProbeUserAgent, whitelisUserAgents) {
whitelisUserAgents = append(whitelisUserAgents, kubeProbeUserAgent)
}
}
func WhitelistFilter(handler FilterHandler) FilterHandler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
for _, userAgent := range whitelisUserAgents {
if strings.Contains(strings.ToLower(r.UserAgent()), userAgent) {
handler(ctx, w, r)
return
}
}
log.Errorf("Forbidden default handler request: %s allow: %s", r.UserAgent(), strings.Join(whitelisUserAgents, ","))
httperrors.ForbiddenError(ctx, w, "Forbidden")
}
}
+1
View File
@@ -37,6 +37,7 @@ func InitApp(options *common_options.BaseOptions, dbAccess bool) *appsrv.Applica
// if dbConn != nil {
// app.SetContext(appsrv.APP_CONTEXT_KEY_DB, dbConn)
//}
appsrv.SetDefaultHandlersWhitelistUserAgents(options.DefaultHandlersWhitelistUserAgents)
if options.EnableAppProfiling {
app.EnableProfiling()
}
+4
View File
@@ -20,6 +20,7 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
)
@@ -77,6 +78,9 @@ func OnBaseOptionsChange(oOpts, nOpts interface{}) bool {
if oldOpts.EnableChangeOwnerAutoRename != newOpts.EnableChangeOwnerAutoRename {
consts.SetChangeOwnerAutoRename(newOpts.EnableChangeOwnerAutoRename)
}
if privatePrrefixesChanged(oldOpts.DefaultHandlersWhitelistUserAgents, newOpts.DefaultHandlersWhitelistUserAgents) {
appsrv.SetDefaultHandlersWhitelistUserAgents(newOpts.DefaultHandlersWhitelistUserAgents)
}
return changed
}
+2
View File
@@ -129,6 +129,8 @@ type BaseOptions struct {
EnableChangeOwnerAutoRename bool `help:"Allows renaming when changing names" default:"false"`
EnableDefaultPolicy bool `help:"Enable defualt policies" default:"true"`
DefaultHandlersWhitelistUserAgents []string `help:"whitelist user agents, default is empty"`
}
const (