From 3eeaa6d9a33f9294ade64c8ff26144fba86a379e Mon Sep 17 00:00:00 2001 From: grm Date: Fri, 18 Sep 2026 13:47:49 +0300 Subject: Security: Add HTTPS and TRUST_PROXY settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A --- internal/auth/cookie.go | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'internal/auth') diff --git a/internal/auth/cookie.go b/internal/auth/cookie.go index 9fd6b6e..8fa394d 100644 --- a/internal/auth/cookie.go +++ b/internal/auth/cookie.go @@ -7,17 +7,26 @@ import ( const CookieName = "session" -func SetSessionCookie(w http.ResponseWriter, token string) { - http.SetCookie(w, &http.Cookie{ +// SetSessionCookie sets the session cookie; secure marks it for https only, +// which the app cannot tell on its own behind a plain-http proxy. +func SetSessionCookie(w http.ResponseWriter, token string, secure bool) { + http.SetCookie(w, sessionCookie(token, int(SessionTTL/time.Second), secure)) +} + +// ClearSessionCookie expires the cookie with the same attributes it was set +// with; browsers only replace a cookie whose Secure flag matches. +func ClearSessionCookie(w http.ResponseWriter, secure bool) { + http.SetCookie(w, sessionCookie("", -1, secure)) +} + +func sessionCookie(value string, maxAge int, secure bool) *http.Cookie { + return &http.Cookie{ Name: CookieName, - Value: token, + Value: value, Path: "/", HttpOnly: true, + Secure: secure, SameSite: http.SameSiteLaxMode, - MaxAge: int(SessionTTL / time.Second), - }) -} - -func ClearSessionCookie(w http.ResponseWriter) { - http.SetCookie(w, &http.Cookie{Name: CookieName, Value: "", Path: "/", HttpOnly: true, MaxAge: -1}) + MaxAge: maxAge, + } } -- cgit v1.2.3