v0.23.0 — CSRF protection on all browser-facing POST endpoints
Controller: - internal/web/csrf.go (new): CsrfProtect middleware, csrfToken/csrfField helpers - auth.go: per-session CSRF token (csrfToken field, csrfTokenForSession method) - server.go: executeTemplate wrapper auto-injects CSRFField+CSRFToken - main.go: wire CsrfProtect on all routes; bump to v0.23.0 - handlers.go, storage_handlers.go, handler_restore.go: executeTemplate - All templates: CSRFField in forms, meta csrf-token, csrfHeaders() JS helper, fetch calls updated; sendBeacon→fetch+keepalive in storage_attach.html Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+28
-3
@@ -757,6 +757,30 @@ self_update:
|
||||
- Session cleanup every 15 minutes
|
||||
- All sessions invalidated on password change
|
||||
- Conditional logout link (hidden when auth is disabled)
|
||||
- Each session stores a dedicated CSRF token (separate 32-byte random value) alongside the session token
|
||||
|
||||
#### CSRF Protection (`internal/web/csrf.go`)
|
||||
|
||||
Synchronizer-token CSRF protection on all browser-facing state-mutating endpoints.
|
||||
|
||||
**How it works:**
|
||||
- `CsrfProtect` middleware wraps all route handlers in `main.go`
|
||||
- Safe methods (GET, HEAD, OPTIONS) pass through without validation
|
||||
- For POST/DELETE/PATCH: reads token from `_csrf` form field or `X-CSRF-Token` request header; constant-time compares against the session's stored CSRF token
|
||||
- On rejection: JSON `{"ok":false,"error":"CSRF token missing or invalid"}` for `/api/` paths; HTTP 403 text page for UI routes
|
||||
- Logs: `[WARN] CSRF rejected: METHOD /path from addr (reason)`
|
||||
|
||||
**Exempt paths (no CSRF check):**
|
||||
- Requests with `Authorization: Bearer ...` header — hub→controller API calls (selfupdate, config/apply). Browsers cannot auto-send Bearer headers, so cross-site requests are impossible on these endpoints.
|
||||
- Auth-disabled mode (`authEnabled() == false`) — CSRF is meaningless when there is no session.
|
||||
|
||||
**Token delivery to templates:**
|
||||
- `executeTemplate(w, r, name, data)` wrapper in `server.go` auto-injects `CSRFField` (`template.HTML` hidden `<input>`) and `CSRFToken` (raw string) into every page's data map
|
||||
- `layout.html` emits `<meta name="csrf-token" content="{{.CSRFToken}}">` and defines `csrfHeaders()` JS function in `<head>` (before page scripts)
|
||||
- Forms: `{{.CSRFField}}` (or `{{$.CSRFField}}` inside `{{range}}` loops — outer scope required)
|
||||
- JS `fetch()` calls: `headers: csrfHeaders()` — returns `{'X-CSRF-Token': metaContent}`
|
||||
- Dynamically-created JS forms: read token from `document.querySelector('meta[name="csrf-token"]').content`
|
||||
- `navigator.sendBeacon()` replaced with `fetch(..., {keepalive: true})` where used — `sendBeacon` cannot send custom headers
|
||||
|
||||
#### Settings Persistence (`internal/settings/settings.go`)
|
||||
|
||||
@@ -1033,8 +1057,9 @@ controller/
|
||||
│ │ └── templates/ # 7 wizard HTML templates (Hungarian)
|
||||
│ ├── recovery/info.go # Recovery info file generator (recovery-info.txt)
|
||||
│ └── web/
|
||||
│ ├── server.go # HTTP server, routing, static files
|
||||
│ ├── auth.go # Session auth, login/logout, session cleanup
|
||||
│ ├── server.go # HTTP server, routing, static files, executeTemplate wrapper
|
||||
│ ├── auth.go # Session auth + per-session CSRF token, login/logout, session cleanup
|
||||
│ ├── csrf.go # CsrfProtect middleware, csrfToken/csrfField helpers
|
||||
│ ├── handlers.go # Page handlers (dashboard, stacks, deploy, backups, etc.)
|
||||
│ ├── handler_restore.go # DR: restore page handler + APIs (scan, restore all, skip)
|
||||
│ ├── storage_handlers.go # Storage API handlers (scan, format, attach, migrate, cleanup, disconnect/reconnect)
|
||||
@@ -1329,7 +1354,7 @@ See `docker-compose.yml` for the full volume configuration.
|
||||
- [ ] Update classification and auto-apply (optional/required/security markers)
|
||||
- [ ] Docker volume backup (`/var/lib/docker/volumes:ro`)
|
||||
- [ ] Raspberry Pi testing (pi-customer-1)
|
||||
- [ ] CSRF protection on POST endpoints
|
||||
- [x] CSRF protection on POST endpoints (v0.23.0)
|
||||
- [ ] Login rate limiting
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user