diff options
| author | grm <grm@eyesin.space> | 2026-09-18 13:47:49 +0300 |
|---|---|---|
| committer | grm <grm@eyesin.space> | 2026-09-18 13:47:49 +0300 |
| commit | 3eeaa6d9a33f9294ade64c8ff26144fba86a379e (patch) | |
| tree | 1c4bf44884ea59f7e3d9ca12008846f08bf72d16 /internal/web/server.go | |
| parent | 254733b0566830a46e5a44c2d3127f57bfaceb65 (diff) | |
| download | blogspace-3eeaa6d9a33f9294ade64c8ff26144fba86a379e.tar.gz blogspace-3eeaa6d9a33f9294ade64c8ff26144fba86a379e.tar.bz2 blogspace-3eeaa6d9a33f9294ade64c8ff26144fba86a379e.zip | |
Security: Add HTTPS and TRUST_PROXY settings
The app only ever speaks plain HTTP, so it could not know the site was
served over TLS: generated links were http:// (the /webadmin bounce
from a blog host sent the login page over http), the session cookie
was never Secure and nothing sent HSTS. HTTPS=true fixes all three;
ClearSessionCookie now uses the same attributes as the set, since a
browser only replaces a cookie whose Secure flag matches.
TRUST_PROXY=true makes the client address the last X-Forwarded-For
entry — the one our proxy appended — so throttling and the log see
real addresses instead of the proxy's; earlier entries are whatever
the client sent and are ignored. Production startup warns when HTTPS
is off.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
Diffstat (limited to 'internal/web/server.go')
| -rw-r--r-- | internal/web/server.go | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/internal/web/server.go b/internal/web/server.go index 12440de..f768ebd 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -43,6 +43,9 @@ func NewServer(cfg *config.Config, st *store.Store) *Server { // site plus the superadmin's root blog, one label below it is a blog, anything // else is a 404. func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if s.cfg.HTTPS { // every subdomain is ours, so the whole site may pin https + w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") + } host := hostname(r.Host) switch { case host == s.cfg.BaseDomain, host == config.RootSubdomain+"."+s.cfg.BaseDomain: @@ -178,13 +181,13 @@ func (s *Server) session(next http.Handler) http.Handler { } claims, err := auth.ParseToken(s.cfg.JWTSecret, c.Value) if err != nil { - auth.ClearSessionCookie(w) + auth.ClearSessionCookie(w, s.cfg.HTTPS) next.ServeHTTP(w, r) return } u, err := s.st.UserByID(r.Context(), claims.UserID) if err != nil || u.Disabled || u.TokenVersion != claims.TokenVersion { - auth.ClearSessionCookie(w) + auth.ClearSessionCookie(w, s.cfg.HTTPS) next.ServeHTTP(w, r) return } |
