security: reject traversal segments before permission checks
This commit is contained in:
@@ -123,6 +123,16 @@ func writeJSONError(w http.ResponseWriter, status int, message string) {
|
|||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
_ = json.NewEncoder(w).Encode(map[string]string{"error": message})
|
_ = json.NewEncoder(w).Encode(map[string]string{"error": message})
|
||||||
}
|
}
|
||||||
|
func unsafePath(p string) bool {
|
||||||
|
p = strings.ReplaceAll(p, "\\", "/")
|
||||||
|
for _, part := range strings.Split(p, "/") {
|
||||||
|
if part == ".." {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func qpath(r *http.Request) string {
|
func qpath(r *http.Request) string {
|
||||||
return strings.Trim(strings.ReplaceAll(r.URL.Query().Get("filepath"), "\\", "/"), "/")
|
return strings.Trim(strings.ReplaceAll(r.URL.Query().Get("filepath"), "\\", "/"), "/")
|
||||||
}
|
}
|
||||||
@@ -167,6 +177,10 @@ func writeCreated(w http.ResponseWriter) { w.WriteHeader(http.StatusCreated) }
|
|||||||
|
|
||||||
func (s *Server) files(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) files(w http.ResponseWriter, r *http.Request) {
|
||||||
a := account(r, s)
|
a := account(r, s)
|
||||||
|
if unsafePath(r.URL.Query().Get("filepath")) {
|
||||||
|
writeJSONError(w, http.StatusBadRequest, "invalid parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
p := qpath(r)
|
p := qpath(r)
|
||||||
m := a.MaskFor(p)
|
m := a.MaskFor(p)
|
||||||
if !m.HasRead() {
|
if !m.HasRead() {
|
||||||
@@ -213,6 +227,10 @@ func (s *Server) newdir(w http.ResponseWriter, r *http.Request) {
|
|||||||
_ = r.ParseMultipartForm(16 << 20)
|
_ = r.ParseMultipartForm(16 << 20)
|
||||||
_ = r.ParseForm()
|
_ = r.ParseForm()
|
||||||
p := qpath(r)
|
p := qpath(r)
|
||||||
|
if unsafePath(r.URL.Query().Get("filepath")) || unsafePath(r.FormValue("filepath")) {
|
||||||
|
writeJSONError(w, http.StatusBadRequest, "invalid parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
if p == "" {
|
if p == "" {
|
||||||
p = strings.Trim(strings.ReplaceAll(r.FormValue("filepath"), "\\", "/"), "/")
|
p = strings.Trim(strings.ReplaceAll(r.FormValue("filepath"), "\\", "/"), "/")
|
||||||
}
|
}
|
||||||
@@ -536,6 +554,10 @@ func (s *Server) shared(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
p := strings.Trim(strings.TrimPrefix(r.URL.Path, "/chfs/shared/"), "/")
|
p := strings.Trim(strings.TrimPrefix(r.URL.Path, "/chfs/shared/"), "/")
|
||||||
|
if unsafePath(p) {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
fi, err := s.Store.Stat(p)
|
fi, err := s.Store.Stat(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
@@ -716,6 +738,10 @@ func (s *Server) webdav(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
vp := strings.Trim(strings.TrimPrefix(r.URL.Path, "/webdav"), "/")
|
vp := strings.Trim(strings.TrimPrefix(r.URL.Path, "/webdav"), "/")
|
||||||
|
if unsafePath(vp) {
|
||||||
|
writeJSONError(w, http.StatusBadRequest, "invalid parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
old := r.URL.Path
|
old := r.URL.Path
|
||||||
r.URL.Path = "/" + vp
|
r.URL.Path = "/" + vp
|
||||||
defer func() { r.URL.Path = old }()
|
defer func() { r.URL.Path = old }()
|
||||||
|
|||||||
Reference in New Issue
Block a user