diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-16 14:02:48 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-16 14:02:48 -0800 |
| commit | 2e459c911031669080bc110059cf2b4b19c5379d (patch) | |
| tree | 60650c8fc5e2d919b5e6fdb4b073b0f0f4d54d8e /web/web.go | |
| parent | 52ea335714f2b495b92f87636c269b73b4067066 (diff) | |
| download | neko-2e459c911031669080bc110059cf2b4b19c5379d.tar.gz neko-2e459c911031669080bc110059cf2b4b19c5379d.tar.bz2 neko-2e459c911031669080bc110059cf2b4b19c5379d.zip | |
Enhance CSRF protection for login page
Login form now includes a CSRF token from the cookie as a hidden form
field. The CSRF middleware accepts tokens from either the X-CSRF-Token
header (for JS clients) or the csrf_token form field (for HTML forms).
Removed /login from the CSRF exclusion list so login POSTs are now
validated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'web/web.go')
| -rw-r--r-- | web/web.go | 10 |
1 files changed, 7 insertions, 3 deletions
@@ -380,11 +380,15 @@ func CSRFMiddleware(cfg *config.Settings, next http.Handler) http.Handler { } path := strings.TrimSuffix(r.URL.Path, "/") - isExcluded := path == "/api/login" || path == "/login" || path == "/api/logout" + isExcluded := path == "/api/login" || path == "/api/logout" if (r.Method == http.MethodPost || r.Method == http.MethodPut || r.Method == http.MethodDelete) && !isExcluded { - headerToken := r.Header.Get("X-CSRF-Token") - if headerToken == "" || headerToken != token { + // Accept token from header (JS clients) or form field (HTML forms) + submittedToken := r.Header.Get("X-CSRF-Token") + if submittedToken == "" { + submittedToken = r.FormValue("csrf_token") + } + if submittedToken == "" || submittedToken != token { http.Error(w, "CSRF token mismatch", http.StatusForbidden) return } |
