diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index de536fcb5..3405f69d1 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -126,8 +126,9 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro mux.HandleFunc("/", embeddedStatic) } - // Wrap everything in CSRF protection - handler := csrfMiddleware(mux) + // Wrap everything in CSRF protection. The /rest prefix should be + // protected, other requests will grant cookies. + handler := csrfMiddleware("/rest", mux) // Wrap everything in basic auth, if user/password is set. if len(cfg.User) > 0 { diff --git a/cmd/syncthing/gui_csrf.go b/cmd/syncthing/gui_csrf.go index 7b23c3631..93c85aa0d 100644 --- a/cmd/syncthing/gui_csrf.go +++ b/cmd/syncthing/gui_csrf.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "sync" "time" @@ -20,7 +21,7 @@ var csrfMut sync.Mutex // Check for CSRF token on /rest/ URLs. If a correct one is not given, reject // the request with 403. For / and /index.html, set a new CSRF cookie if none // is currently set. -func csrfMiddleware(next http.Handler) http.Handler { +func csrfMiddleware(prefix string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Allow requests carrying a valid API key if validAPIKey(r.Header.Get("X-API-Key")) { @@ -29,7 +30,7 @@ func csrfMiddleware(next http.Handler) http.Handler { } // Allow requests for the front page, and set a CSRF cookie if there isn't already a valid one. - if r.URL.Path == "/" || r.URL.Path == "/index.html" { + if !strings.HasPrefix(r.URL.Path, prefix) { cookie, err := r.Cookie("CSRF-Token") if err != nil || !validCsrfToken(cookie.Value) { cookie = &http.Cookie{