From f1b1d71f4060fe7c4ac29b1cbd94ab11430766d6 Mon Sep 17 00:00:00 2001 From: MickaelK Date: Wed, 15 Jan 2025 01:09:53 +1100 Subject: [PATCH] feature (signature): protect url param via signature --- server/common/config.go | 1 + server/common/constants.go | 18 ++++++++++-------- server/ctrl/session.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/server/common/config.go b/server/common/config.go index 5403743c..ab45fb38 100644 --- a/server/common/config.go +++ b/server/common/config.go @@ -106,6 +106,7 @@ func NewConfiguration() Configuration { Elmnts: []FormElement{ FormElement{Name: "iframe", Type: "text", Default: "", Description: "list of domains who can use the application from an iframe. eg: https://www.filestash.app http://example.com"}, FormElement{Name: "enable_chromecast", Type: "boolean", Default: true, Description: "Enable users to stream content on a chromecast device. This feature requires the browser to access google's server to download the chromecast SDK."}, + FormElement{Name: "signature", Type: "text", Default: "", Description: "Enforce signature when using URL parameters in the authentication process"}, }, }, }, diff --git a/server/common/constants.go b/server/common/constants.go index 5035d607..e96f5074 100644 --- a/server/common/constants.go +++ b/server/common/constants.go @@ -56,14 +56,15 @@ func init() { } var ( - BUILD_REF string - BUILD_DATE string - LICENSE string = "agpl" - SECRET_KEY string - SECRET_KEY_DERIVATE_FOR_PROOF string - SECRET_KEY_DERIVATE_FOR_ADMIN string - SECRET_KEY_DERIVATE_FOR_USER string - SECRET_KEY_DERIVATE_FOR_HASH string + BUILD_REF string + BUILD_DATE string + LICENSE string = "agpl" + SECRET_KEY string + SECRET_KEY_DERIVATE_FOR_PROOF string + SECRET_KEY_DERIVATE_FOR_ADMIN string + SECRET_KEY_DERIVATE_FOR_USER string + SECRET_KEY_DERIVATE_FOR_HASH string + SECRET_KEY_DERIVATE_FOR_SIGNATURE string ) /* @@ -76,6 +77,7 @@ func InitSecretDerivate(secret string) { SECRET_KEY_DERIVATE_FOR_ADMIN = Hash("ADMIN_"+SECRET_KEY, len(SECRET_KEY)) SECRET_KEY_DERIVATE_FOR_USER = Hash("USER_"+SECRET_KEY, len(SECRET_KEY)) SECRET_KEY_DERIVATE_FOR_HASH = Hash("HASH_"+SECRET_KEY, len(SECRET_KEY)) + SECRET_KEY_DERIVATE_FOR_SIGNATURE = Hash("SGN_"+SECRET_KEY, len(SECRET_KEY)) } var base = os.Getenv("FILESTASH_BASE") diff --git a/server/ctrl/session.go b/server/ctrl/session.go index da19ebc9..722f722e 100644 --- a/server/ctrl/session.go +++ b/server/ctrl/session.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "os" + "slices" "strings" "text/template" "time" @@ -351,6 +352,33 @@ func SessionAuthMiddleware(ctx *App, res http.ResponseWriter, req *http.Request) if decodedState, err := base64.StdEncoding.DecodeString(state); err == nil { stateStruct := map[string]string{} json.Unmarshal(decodedState, &stateStruct) + + // check variables are "legit" + attributes := "" + signature := "" + fields := strings.Split(Config.Get("features.protection.signature").String(), ",") + for k, v := range stateStruct { + if k == "signature" { + signature = v + } + if slices.Contains(fields, k) { + attributes += fmt.Sprintf("%s[%s] ", k, v) + } + } + attributes = strings.TrimSpace(attributes) + v, err := DecryptString(SECRET_KEY_DERIVATE_FOR_SIGNATURE, signature) + if err != nil || attributes != v { + v, _ = EncryptString(SECRET_KEY_DERIVATE_FOR_SIGNATURE, attributes) + Log.Debug("callback signature is required, signature=%s", v) + http.Redirect( + res, req, + WithBase("/?error=Invalid%20Signature&trace=signature is not correct"), + http.StatusTemporaryRedirect, + ) + return + } + + // populate variable for key, value := range stateStruct { if templateBind[key] != "" { continue