fileserver: Reject ADS and short name paths; trim trailing dots and spaces on Windows (#5148)

* fileserver: Reject ADS and short name paths

* caddyhttp: Trim trailing space and dot on Windows

Windows ignores trailing dots and spaces in filenames.

* Fix test

* Adjust path filters

* Revert Windows test

* Actually revert the test

* Just check for colons
This commit is contained in:
Matt Holt 2022-10-18 21:55:25 -06:00 committed by GitHub
parent 72e7edda1f
commit 4bf6cb4199
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 1 deletions

View file

@ -87,7 +87,7 @@ func TestSanitizedPathJoin(t *testing.T) {
} }
actual := SanitizedPathJoin(tc.inputRoot, u.Path) actual := SanitizedPathJoin(tc.inputRoot, u.Path)
if actual != tc.expect { if actual != tc.expect {
t.Errorf("Test %d: SanitizedPathJoin('%s', '%s') => %s (expected '%s')", t.Errorf("Test %d: SanitizedPathJoin('%s', '%s') => '%s' (expected '%s')",
i, tc.inputRoot, tc.inputPath, actual, tc.expect) i, tc.inputRoot, tc.inputPath, actual, tc.expect)
} }
} }

View file

@ -26,6 +26,7 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"runtime"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -232,6 +233,19 @@ func (fsrv *FileServer) Provision(ctx caddy.Context) error {
func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
if runtime.GOOS == "windows" {
// reject paths with Alternate Data Streams (ADS)
if strings.Contains(r.URL.Path, ":") {
return caddyhttp.Error(http.StatusBadRequest, fmt.Errorf("illegal ADS path"))
}
// reject paths with "8.3" short names
trimmedPath := strings.TrimRight(r.URL.Path, ". ") // Windows ignores trailing dots and spaces, sigh
if len(path.Base(trimmedPath)) <= 12 && strings.Contains(trimmedPath, "~") {
return caddyhttp.Error(http.StatusBadRequest, fmt.Errorf("illegal short name"))
}
// both of those could bypass file hiding or possibly leak information even if the file is not hidden
}
filesToHide := fsrv.transformHidePaths(repl) filesToHide := fsrv.transformHidePaths(repl)
root := repl.ReplaceAll(fsrv.Root, ".") root := repl.ReplaceAll(fsrv.Root, ".")