mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
safeweb: add StrictTransportSecurityOptions config (#13679)
Add the ability to specify Strict-Transport-Security options in response to BrowserMux HTTP requests in safeweb. Updates https://github.com/tailscale/corp/issues/23375 Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
This commit is contained in:
parent
dc60c8d786
commit
a3c6a3a34f
@ -94,6 +94,10 @@
|
|||||||
`object-src 'self'`, // disallow embedding of resources from other origins
|
`object-src 'self'`, // disallow embedding of resources from other origins
|
||||||
}, "; ")
|
}, "; ")
|
||||||
|
|
||||||
|
// The default Strict-Transport-Security header. This header tells the browser
|
||||||
|
// to exclusively use HTTPS for all requests to the origin for the next year.
|
||||||
|
var DefaultStrictTransportSecurityOptions = "max-age=31536000"
|
||||||
|
|
||||||
// Config contains the configuration for a safeweb server.
|
// Config contains the configuration for a safeweb server.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// SecureContext specifies whether the Server is running in a secure (HTTPS) context.
|
// SecureContext specifies whether the Server is running in a secure (HTTPS) context.
|
||||||
@ -134,6 +138,12 @@ type Config struct {
|
|||||||
// CookiesSameSiteLax specifies whether to use SameSite=Lax in cookies. The
|
// CookiesSameSiteLax specifies whether to use SameSite=Lax in cookies. The
|
||||||
// default is to set SameSite=Strict.
|
// default is to set SameSite=Strict.
|
||||||
CookiesSameSiteLax bool
|
CookiesSameSiteLax bool
|
||||||
|
|
||||||
|
// StrictTransportSecurityOptions specifies optional directives for the
|
||||||
|
// Strict-Transport-Security header sent in response to requests made to the
|
||||||
|
// BrowserMux when SecureContext is true.
|
||||||
|
// If empty, it defaults to max-age of 1 year.
|
||||||
|
StrictTransportSecurityOptions string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) setDefaults() error {
|
func (c *Config) setDefaults() error {
|
||||||
@ -274,6 +284,9 @@ func (s *Server) serveBrowser(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Content-Security-Policy", s.csp)
|
w.Header().Set("Content-Security-Policy", s.csp)
|
||||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
w.Header().Set("Referer-Policy", "same-origin")
|
w.Header().Set("Referer-Policy", "same-origin")
|
||||||
|
if s.SecureContext {
|
||||||
|
w.Header().Set("Strict-Transport-Security", cmp.Or(s.StrictTransportSecurityOptions, DefaultStrictTransportSecurityOptions))
|
||||||
|
}
|
||||||
s.csrfProtect(s.BrowserMux).ServeHTTP(w, r)
|
s.csrfProtect(s.BrowserMux).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/gorilla/csrf"
|
"github.com/gorilla/csrf"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -561,3 +562,50 @@ func TestGetMoreSpecificPattern(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStrictTransportSecurityOptions(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
options string
|
||||||
|
secureContext bool
|
||||||
|
expect string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "off by default",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default HSTS options in the secure context",
|
||||||
|
secureContext: true,
|
||||||
|
expect: DefaultStrictTransportSecurityOptions,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom options sent in the secure context",
|
||||||
|
options: DefaultStrictTransportSecurityOptions + "; includeSubDomains",
|
||||||
|
secureContext: true,
|
||||||
|
expect: DefaultStrictTransportSecurityOptions + "; includeSubDomains",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
h := &http.ServeMux{}
|
||||||
|
h.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("ok"))
|
||||||
|
}))
|
||||||
|
s, err := NewServer(Config{BrowserMux: h, SecureContext: tt.secureContext, StrictTransportSecurityOptions: tt.options})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
req := httptest.NewRequest("GET", "/", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
s.h.Handler.ServeHTTP(w, req)
|
||||||
|
resp := w.Result()
|
||||||
|
|
||||||
|
if cmp.Diff(tt.expect, resp.Header.Get("Strict-Transport-Security")) != "" {
|
||||||
|
t.Fatalf("HSTS want: %q; got: %q", tt.expect, resp.Header.Get("Strict-Transport-Security"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user