feat(security): HSTS og en lukket Permissions-Policy på hvert svar
To headere, appen ikke satte, og som begge følger af, hvad den allerede er. Sessionen bor i en __Host-cookie, der kun findes over HTTPS — hele modellen forudsætter TLS. Uden HSTS holder den forudsætning ikke mod en netværksangriber: den allerførste navigation kan strippes til http://, og cookien rækkes over i klartekst, før Secure-flaget nogensinde kommer i spil. HSTS lukker vinduet, og den er sat på nøjagtig samme betingelse som cookiens Secure-flag (secureCookies), så en dev-instans på ren HTTP aldrig bliver bedt om et certifikat, den ikke har. To år, underdomæner med; ingen preload — at blive hard-kodet ind i browsere er en beslutning for domænets ejer, ikke for en selv-hostet app. verdande beder aldrig om kamera, mikrofon eller placering, så den sikreste Permissions-Policy er at slå dem alle fra: et indsat element kan ikke bede om det, siden selv har afvist. Navngivet felt for felt frem for med et jokertegn, fordi jokertegns-formen ikke forstås ens af alle browsere, og en regel, en browser ignorerer, er ingen regel. Prøve på begge: HSTS følger HTTPS og udebliver over HTTP, og Permissions-Policy lukker for kameraet uanset skema. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
3e52eea2da
commit
8a87cfeb44
@@ -665,6 +665,26 @@ func (s *Server) securityHeaders(next http.Handler) http.Handler {
|
||||
h.Set("X-Frame-Options", "DENY")
|
||||
h.Set("Referrer-Policy", "same-origin")
|
||||
h.Set("Content-Security-Policy", s.csp)
|
||||
// The session lives in a __Host- cookie that only exists over HTTPS, so the
|
||||
// whole security model already assumes TLS. HSTS is what makes that
|
||||
// assumption hold against a network attacker: without it, the very first
|
||||
// navigation can be stripped to http:// and the cookie handed over in the
|
||||
// clear. Gated on the same condition as the cookie's Secure flag, so a
|
||||
// plain-HTTP dev instance is never told to demand a certificate it cannot
|
||||
// present. Two years, subdomains included; no preload directive, because
|
||||
// asking to be hard-coded into browsers is a decision the operator makes
|
||||
// for their domain, not one a self-hosted app makes for them.
|
||||
if s.secureCookies() {
|
||||
h.Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
|
||||
}
|
||||
// verdande uses none of the powerful browser features, so the safest policy
|
||||
// is to turn them all off: an injected element cannot ask for the camera,
|
||||
// the microphone or the location if the page itself has already declined
|
||||
// them. Named explicitly rather than with a wildcard because the wildcard
|
||||
// form of this header is not universally understood, and a directive a
|
||||
// browser ignores is not a control.
|
||||
h.Set("Permissions-Policy", "camera=(), microphone=(), geolocation=(), "+
|
||||
"payment=(), usb=(), interest-cohort=()")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user