docs: document /data/setup-token and close phase 14
14.C needed no code: the setup link is already mirrored to /data/setup-token at 0600 and removed once setup completes. What was missing is the reason to prefer it — a deployment whose container logs ship to a central aggregator otherwise leaves a live bearer token in that pipeline for ten minutes, and in whatever retains it afterwards. The reverse-proxy section gains the one requirement 14.A introduces: pass the original Host header through. Everything else about security stays the proxy's non-problem, which is the point of emitting the headers from the panel. Phase 14 leaves the plan (the file describes only unfinished work), but its section A keeps what was deliberately left open: the accepted risk for clients sending neither Sec-Fetch-Site nor Origin, the decision not to add session-bound CSRF tokens and what would justify revisiting it, and the fact that XSS inside the panel's own origin is answered by html/template and the CSP rather than by either of those. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,37 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- panel: security headers on every response — `Content-Security-Policy`,
|
||||
`X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, and
|
||||
`Strict-Transport-Security` where the deployment is HTTPS-only. They are
|
||||
emitted by the panel itself, so the reverse proxy still needs no security
|
||||
configuration of its own.
|
||||
- panel: state-changing requests are now checked against the panel's own
|
||||
origin (`Sec-Fetch-Site`, falling back to `Origin` vs `Host`). This closes
|
||||
cross-site request forgery from a *neighbouring host on the same domain* —
|
||||
a CMS or a forgotten staging subdomain next to the panel — which the session
|
||||
cookie's `SameSite=Lax` counts as same-site and therefore cannot stop. A
|
||||
request that sends neither header is still let through, so genuinely ancient
|
||||
browsers keep working. **The reverse proxy must pass the original `Host`
|
||||
header through** (every shipped fragment already does); one that rewrites it
|
||||
makes the panel refuse every form submission, and the log line names both
|
||||
the `Origin` and the `Host` it compared.
|
||||
- panel: the session cookie is now named `__Host-selfpost_session` wherever it
|
||||
is `Secure` (the standard deployment), which makes the browser enforce that
|
||||
no other host can set or overwrite it. **Upgrading signs the administrator
|
||||
out once.** With `PANEL_COOKIE_SECURE=false` the old name is kept, because
|
||||
the prefix is invalid without TLS. Signing out clears both names.
|
||||
- panel: if a request arrives with two cookies of the session cookie's name —
|
||||
what a neighbouring host does when it overwrites the session — the request
|
||||
counts as signed out and the log says so, instead of the panel silently
|
||||
picking the other host's value and looping back to the login form forever.
|
||||
- panel: the layout's stylesheet moved to `/static/panel.css` and the
|
||||
confirmation prompts on destructive buttons moved into `/static/panel.js`.
|
||||
No visible change; the panel's CSP allows no inline script or style, and
|
||||
this is what keeps that policy free of exemptions.
|
||||
- docs: the first-run setup link is also written to `/data/setup-token`
|
||||
(`0600`) — documented in the README as the way to read it without the token
|
||||
passing through a container-log pipeline.
|
||||
- panel: new **Status** page — supervised processes, mail queue, TLS
|
||||
certificate expiry, milter sockets and the server's own hostname/reverse-DNS
|
||||
(FCrDNS) check — and it is now the panel's landing page. The local checks
|
||||
|
||||
Reference in New Issue
Block a user