Merge SEC-04: API security headers

This commit is contained in:
2026-03-13 00:50:27 -07:00
2 changed files with 69 additions and 1 deletions

View File

@@ -154,10 +154,20 @@ func (s *Server) Handler() http.Handler {
}
uiSrv.Register(mux)
// Apply global middleware: request logging.
// Apply global middleware: request logging and security headers.
// Rate limiting is applied per-route above (login, token/validate).
var root http.Handler = mux
root = middleware.RequestLogger(s.logger)(root)
// Security (SEC-04): apply baseline security headers to ALL responses
// (both API and UI). These headers are safe for every content type:
// - X-Content-Type-Options prevents MIME-sniffing attacks.
// - Strict-Transport-Security enforces HTTPS for 2 years.
// - Cache-Control prevents caching of authenticated responses.
// The UI sub-mux already sets these plus CSP/X-Frame-Options/Referrer-Policy
// which will override where needed (last Set wins before WriteHeader).
root = globalSecurityHeaders(root)
return root
}
@@ -1309,6 +1319,20 @@ func extractBearerFromRequest(r *http.Request) (string, error) {
// docsSecurityHeaders adds the same defensive HTTP headers as the UI sub-mux
// to the /docs and /docs/openapi.yaml endpoints.
//
// globalSecurityHeaders sets baseline security headers on every response.
// Security (SEC-04): API responses previously lacked X-Content-Type-Options,
// HSTS, and Cache-Control. These three headers are safe for all content types
// and do not interfere with JSON API clients or the HTMX UI.
func globalSecurityHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h := w.Header()
h.Set("X-Content-Type-Options", "nosniff")
h.Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
h.Set("Cache-Control", "no-store")
next.ServeHTTP(w, r)
})
}
// Security (DEF-09): without these headers the Swagger UI HTML page is
// served without CSP, X-Frame-Options, or HSTS, leaving it susceptible
// to clickjacking and MIME-type confusion in browsers.