[SEC-2191] Add security headers with sensible default values. (#21656)
* Add security headers with sensible default values. * Add test to check that default security headers are added to http responses * Also test the static handler.
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
544304d1c6
Коммит
62428467dc
@@ -235,6 +235,11 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Strict-Transport-Security", fmt.Sprintf("max-age=%d", *c.App.Config().ServiceSettings.TLSStrictTransportMaxAge))
|
w.Header().Set("Strict-Transport-Security", fmt.Sprintf("max-age=%d", *c.App.Config().ServiceSettings.TLSStrictTransportMaxAge))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hardcoded sensible default values for these security headers. Feel free to override in proxy or ingress
|
||||||
|
w.Header().Set("Permissions-Policy", "")
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("Referrer-Policy", "no-referrer")
|
||||||
|
|
||||||
cloudCSP := ""
|
cloudCSP := ""
|
||||||
if c.App.Channels().License().IsCloud() || *c.App.Config().ServiceSettings.SelfHostedPurchase {
|
if c.App.Channels().License().IsCloud() || *c.App.Config().ServiceSettings.SelfHostedPurchase {
|
||||||
cloudCSP = " js.stripe.com/v3"
|
cloudCSP = " js.stripe.com/v3"
|
||||||
|
|||||||
@@ -59,6 +59,44 @@ func TestHandlerServeHTTPErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handlerForServeDefaultSecurityHeaders(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandlerServeDefaultSecurityHeaders(t *testing.T) {
|
||||||
|
th := SetupWithStoreMock(t)
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
web := New(th.Server)
|
||||||
|
handler := web.NewHandler(handlerForServeDefaultSecurityHeaders)
|
||||||
|
|
||||||
|
paths := []string{
|
||||||
|
"/api/v4/test", // API
|
||||||
|
"/static/manifest.json", // this should always exist. Static files have their own handler
|
||||||
|
// Note that the plugin handler isn't tested, also plugins may support arbitrary functionality
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range paths {
|
||||||
|
request := httptest.NewRequest("GET", path, nil)
|
||||||
|
|
||||||
|
response := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(response, request)
|
||||||
|
|
||||||
|
// header.Get returns a "" also if the header doesn't exist so we check that there is at least
|
||||||
|
// one Permissions-Policy header and their value is "". We check with .Values() as it canonicalizes
|
||||||
|
// the key.
|
||||||
|
permissionsPolicyHeader := response.Header().Get("Permissions-Policy")
|
||||||
|
permissionsPolicyHeaderValues := response.Header().Values("Permissions-Policy")
|
||||||
|
|
||||||
|
contentTypeOptionsHeader := response.Header().Get("X-Content-Type-Options")
|
||||||
|
referrerPolicyHeader := response.Header().Get("Referrer-Policy")
|
||||||
|
|
||||||
|
assert.NotEqualf(t, 0, len(permissionsPolicyHeaderValues), "Permissions-Policy header doesn't exist")
|
||||||
|
assert.Equal(t, "", permissionsPolicyHeader, "Permissions-Policy is not empty")
|
||||||
|
assert.Equal(t, "nosniff", contentTypeOptionsHeader)
|
||||||
|
assert.Equal(t, "no-referrer", referrerPolicyHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func handlerForHTTPSecureTransport(c *Context, w http.ResponseWriter, r *http.Request) {
|
func handlerForHTTPSecureTransport(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,11 @@ func staticFilesHandler(handler http.Handler) http.Handler {
|
|||||||
w.Header().Set("Cache-Control", "max-age=31556926, public")
|
w.Header().Set("Cache-Control", "max-age=31556926, public")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hardcoded sensible default values for these security headers. Feel free to override in proxy or ingress
|
||||||
|
w.Header().Set("Permissions-Policy", "")
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("Referrer-Policy", "no-referrer")
|
||||||
|
|
||||||
if strings.HasSuffix(r.URL.Path, "/") {
|
if strings.HasSuffix(r.URL.Path, "/") {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user