Make the HSTS max-age configurable with HSTS_MAX_AGE (closes #271)
check / check (push) Waiting to run

HSTS_MAX_AGE, a Go duration, sets the max-age of the
Strict-Transport-Security header. Unset, it is ten years (87600h);
0 sends no header at all. A negative value, or one that is not a
whole number of seconds, stops startup like an unparseable one.
includeSubDomains and preload stay in the header. The value is shown
on /settings and in the startup log, and the README's HSTS section
now says what each part of the header commits the operator to.

Model: opus-5-5
This commit was merged in pull request #515.
This commit is contained in:
2026-10-13 03:27:24 +02:00
parent 9199544999
commit 957de7f99f
7 changed files with 244 additions and 24 deletions
+12 -6
View File
@@ -8,6 +8,7 @@ import (
"net"
"net/http"
"net/url"
"strconv"
"sync"
"time"
@@ -535,18 +536,23 @@ func (s *Middleware) MetricsAuth() func(http.Handler) http.Handler {
}
// SecurityHeaders returns middleware that sets production security
// headers on every response: HSTS, X-Content-Type-Options,
// X-Frame-Options, CSP, Referrer-Policy, and Permissions-Policy.
// headers on every response: HSTS (unless HSTS_MAX_AGE is zero),
// X-Content-Type-Options, X-Frame-Options, CSP, Referrer-Policy, and
// Permissions-Policy.
func (s *Middleware) SecurityHeaders() func(http.Handler) http.Handler {
maxAge := s.params.Config.HSTSMaxAge
hsts := "max-age=" + strconv.FormatInt(int64(maxAge/time.Second), 10) +
"; includeSubDomains; preload"
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(
w http.ResponseWriter,
r *http.Request,
) {
w.Header().Set(
"Strict-Transport-Security",
"max-age=63072000; includeSubDomains; preload",
)
if maxAge > 0 {
w.Header().Set("Strict-Transport-Security", hsts)
}
w.Header().Set(
"X-Content-Type-Options", "nosniff",
)