Disallow access in publicly exposed services (#1761)

* Add security against publicly exposed services
* Add trusted proxies setting, validate proxy chain against internet access
* Validate chain on local proxies too
* Move authentication handler to separate file
* Add startup check and log if tripwire is active

Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
kermieisinthehouse
2021-10-04 07:16:01 +00:00
committed by GitHub
parent dcf58b99a6
commit f1da6cb1b2
12 changed files with 344 additions and 62 deletions

View File

@@ -8,7 +8,6 @@ import (
"fmt"
"io/fs"
"net/http"
"net/url"
"os"
"path"
"runtime/debug"
@@ -29,7 +28,6 @@ import (
"github.com/stashapp/stash/pkg/manager"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/session"
"github.com/stashapp/stash/pkg/utils"
)
@@ -37,65 +35,6 @@ var version string
var buildstamp string
var githash string
func allowUnauthenticated(r *http.Request) bool {
return strings.HasPrefix(r.URL.Path, "/login") || r.URL.Path == "/css"
}
func authenticateHandler() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userID, err := manager.GetInstance().SessionStore.Authenticate(w, r)
if err != nil {
if err != session.ErrUnauthorized {
w.WriteHeader(http.StatusInternalServerError)
_, err = w.Write([]byte(err.Error()))
if err != nil {
logger.Error(err)
}
return
}
// unauthorized error
w.Header().Add("WWW-Authenticate", `FormBased`)
w.WriteHeader(http.StatusUnauthorized)
return
}
c := config.GetInstance()
ctx := r.Context()
// handle redirect if no user and user is required
if userID == "" && c.HasCredentials() && !allowUnauthenticated(r) {
// if we don't have a userID, then redirect
// if graphql was requested, we just return a forbidden error
if r.URL.Path == "/graphql" {
w.Header().Add("WWW-Authenticate", `FormBased`)
w.WriteHeader(http.StatusUnauthorized)
return
}
// otherwise redirect to the login page
u := url.URL{
Path: "/login",
}
q := u.Query()
q.Set(returnURLParam, r.URL.Path)
u.RawQuery = q.Encode()
http.Redirect(w, r, u.String(), http.StatusFound)
return
}
ctx = session.SetCurrentUserID(ctx, userID)
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
}
const loginEndPoint = "/login"
func Start(uiBox embed.FS, loginUIBox embed.FS) {
initialiseImages()
@@ -274,7 +213,7 @@ func Start(uiBox embed.FS, loginUIBox embed.FS) {
}
uiRoot, err := fs.Sub(uiBox, uiRootDir)
if err != nil {
panic(error.Error(err))
panic(err)
}
http.FileServer(http.FS(uiRoot)).ServeHTTP(w, r)
}