From 136c0e2c964b8b4fd27ee9a6f68f02dd2878d4ae Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Wed, 25 Oct 2023 10:11:54 +0200 Subject: [PATCH] Fix: Use a default maxSecretSize and limit the payload read (#144) --- api.go | 15 +++++++++++++++ pkg/customization/customize.go | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/api.go b/api.go index 7f000c7..82de183 100644 --- a/api.go +++ b/api.go @@ -55,6 +55,13 @@ func (a apiServer) Register(r *mux.Router) { } func (a apiServer) handleCreate(res http.ResponseWriter, r *http.Request) { + if cust.MaxSecretSize > 0 { + // As a safeguard against HUGE payloads behind a misconfigured + // proxy we take double the maximum secret size after which we + // just close the read and cut the connection to the sender. + r.Body = http.MaxBytesReader(res, r.Body, cust.MaxSecretSize*2) //nolint:gomnd + } + var ( expiry = cfg.SecretExpiry secret string @@ -69,6 +76,14 @@ func (a apiServer) handleCreate(res http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.Header.Get("Content-Type"), "application/json") { tmp := apiRequest{} if err := json.NewDecoder(r.Body).Decode(&tmp); err != nil { + if _, ok := err.(*http.MaxBytesError); ok { + a.collector.CountSecretCreateError(errorReasonSecretSize) + // We don't do an error response here as the MaxBytesReader + // automatically cuts the ResponseWriter and we simply cannot + // answer them. + return + } + a.collector.CountSecretCreateError(errorReasonInvalidJSON) a.errorResponse(res, http.StatusBadRequest, err, "decoding request body") return diff --git a/pkg/customization/customize.go b/pkg/customization/customize.go index a8b2057..f7b3550 100644 --- a/pkg/customization/customize.go +++ b/pkg/customization/customize.go @@ -12,6 +12,13 @@ import ( "gopkg.in/yaml.v2" ) +// Frontend has a max attachment size of 64MiB as the base64 encoding +// will break afterwards. Therefore we use a maximum secret size of +// 65MiB and increase it by double base64 encoding: +// +// 65 MiB * 16/9 (twice 4/3 base64 size increase) +const defaultMaxSecretSize = 65 * 1024 * 1024 * (16 / 9) // = 115.6MiB + type ( // Customize holds the structure of the customization file Customize struct { @@ -78,4 +85,8 @@ func (c *Customize) applyFixes() { if len(c.AppTitle) == 0 { c.AppTitle = "OTS - One Time Secrets" } + + if c.MaxSecretSize == 0 { + c.MaxSecretSize = defaultMaxSecretSize + } }