From 857b9e577378f28eaa26babe560ea5f0d758811c Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Wed, 24 Apr 2019 13:29:11 -0700 Subject: [PATCH] cmd/pomerium: redirect http and add hsts headers (#92) --- authenticate/handlers.go | 8 +++++--- cmd/pomerium/main.go | 16 +++++++++++++++- internal/middleware/middleware.go | 21 --------------------- proxy/handlers.go | 8 ++++---- 4 files changed, 24 insertions(+), 29 deletions(-) diff --git a/authenticate/handlers.go b/authenticate/handlers.go index 74be885f8..1a0d44f46 100644 --- a/authenticate/handlers.go +++ b/authenticate/handlers.go @@ -16,11 +16,13 @@ import ( "github.com/pomerium/pomerium/internal/version" ) -// securityHeaders corresponds to HTTP response headers that help to protect against protocol -// downgrade attacks and cookie hijacking. +// securityHeaders corresponds to HTTP response headers that help to protect +// against protocol downgrade attacks and cookie hijacking. +// // https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers +// https://https.cio.gov/hsts/ var securityHeaders = map[string]string{ - "Strict-Transport-Security": "max-age=31536000", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload", "X-Frame-Options": "DENY", "X-Content-Type-Options": "nosniff", "X-XSS-Protection": "1; mode=block", diff --git a/cmd/pomerium/main.go b/cmd/pomerium/main.go index baa9dcd7f..201a3bc97 100644 --- a/cmd/pomerium/main.go +++ b/cmd/pomerium/main.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "os" + "time" "google.golang.org/grpc" @@ -102,6 +103,7 @@ func main() { if proxyService != nil { topMux.Handle("/", proxyService.Handler()) } + httpOpts := &https.Options{ Addr: mainOpts.Addr, Cert: mainOpts.Cert, @@ -110,6 +112,18 @@ func main() { KeyFile: mainOpts.KeyFile, } - log.Fatal().Err(https.ListenAndServeTLS(httpOpts, topMux, grpcServer)).Msg("cmd/pomerium: https serve failure") + // redirect http to https + srv := &http.Server{ + ReadTimeout: 5 * time.Second, + WriteTimeout: 5 * time.Second, + Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Connection", "close") + url := fmt.Sprintf("https://%s%s", r.Host, r.URL.String()) + http.Redirect(w, r, url, http.StatusMovedPermanently) + }), + } + go func() { log.Fatal().Err(srv.ListenAndServe()).Msg("cmd/pomerium: http server") }() + + log.Fatal().Err(https.ListenAndServeTLS(httpOpts, topMux, grpcServer)).Msg("cmd/pomerium: https server") } diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 8f04680da..1e845fb4e 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -129,27 +129,6 @@ func ValidateHost(mux map[string]http.Handler) func(next http.Handler) http.Hand } } -// RequireHTTPS reroutes a HTTP request to HTTPS -// todo(bdd) : this is unreliable unless behind another reverser proxy -// todo(bdd) : header age seems extreme -func RequireHTTPS(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Strict-Transport-Security", "max-age=31536000") - // todo(bdd) : scheme and x-forwarded-proto cannot be trusted if not behind another load balancer - if (r.URL.Scheme == "http" && r.Header.Get("X-Forwarded-Proto") == "http") || &r.TLS == nil { - dest := &url.URL{ - Scheme: "https", - Host: r.Host, - Path: r.URL.Path, - RawQuery: r.URL.RawQuery, - } - http.Redirect(w, r, dest.String(), http.StatusMovedPermanently) - return - } - next.ServeHTTP(w, r) - }) -} - // Healthcheck endpoint middleware useful to setting up a path like // `/ping` that load balancers or uptime testing external services // can make a request before hitting any routes. It's also convenient diff --git a/proxy/handlers.go b/proxy/handlers.go index 3305429ed..d50f66e32 100644 --- a/proxy/handlers.go +++ b/proxy/handlers.go @@ -24,9 +24,10 @@ var ( ) var securityHeaders = map[string]string{ - "X-Content-Type-Options": "nosniff", - "X-Frame-Options": "SAMEORIGIN", - "X-XSS-Protection": "1; mode=block", + "X-Content-Type-Options": "nosniff", + "X-Frame-Options": "SAMEORIGIN", + "X-XSS-Protection": "1; mode=block", + "Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload", // 1 year } // StateParameter holds the redirect id along with the session id. @@ -62,7 +63,6 @@ func (p *Proxy) Handler() http.Handler { Msg("proxy: request") })) c = c.Append(middleware.SetHeaders(securityHeaders)) - c = c.Append(middleware.RequireHTTPS) c = c.Append(middleware.ForwardedAddrHandler("fwd_ip")) c = c.Append(middleware.RemoteAddrHandler("ip")) c = c.Append(middleware.UserAgentHandler("user_agent"))