From c207920500d1d55c21d7b7dbb27ba213394ce369 Mon Sep 17 00:00:00 2001 From: Eric V Date: Wed, 2 May 2018 23:27:34 -0700 Subject: [PATCH] Added HTTP security headers to web.go (#3583) Signed-off-by: Eric Valenzuela --- web/web.go | 15 ++++++++++++++- web/web_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/web/web.go b/web/web.go index 76bbf373d3..a54cd04c5d 100644 --- a/web/web.go +++ b/web/web.go @@ -71,6 +71,17 @@ import ( var localhostRepresentations = []string{"127.0.0.1", "localhost"} +// secureHeadersMiddleware adds common HTTP security headers to responses. +func secureHeadersMiddleware(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("X-XSS-Protection", "1; mode=block") + w.Header().Add("X-Content-Type-Options", "nosniff") + w.Header().Add("X-Frame-Options", "SAMEORIGIN") + w.Header().Add("Content-Security-Policy", "frame-ancestors 'self'") + h.ServeHTTP(w, r) + }) +} + var ( requestDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ @@ -478,8 +489,10 @@ func (h *Handler) Run(ctx context.Context) error { errlog := stdlog.New(log.NewStdlibAdapter(level.Error(h.logger)), "", 0) + withSecureHeaders := nethttp.Middleware(opentracing.GlobalTracer(), secureHeadersMiddleware(mux), operationName) + httpSrv := &http.Server{ - Handler: nethttp.Middleware(opentracing.GlobalTracer(), mux, operationName), + Handler: withSecureHeaders, ErrorLog: errlog, ReadTimeout: h.options.ReadTimeout, } diff --git a/web/web_test.go b/web/web_test.go index d94f85c7eb..359a65073f 100644 --- a/web/web_test.go +++ b/web/web_test.go @@ -83,6 +83,54 @@ func TestGlobalURL(t *testing.T) { } } +func TestEndpointHeaders(t *testing.T) { + t.Parallel() + dbDir, err := ioutil.TempDir("", "tsdb-ready") + + testutil.Ok(t, err) + + defer os.RemoveAll(dbDir) + + db, err := libtsdb.Open(dbDir, nil, nil, nil) + + testutil.Ok(t, err) + + opts := &Options{ + ListenAddress: ":9095", + ReadTimeout: 30 * time.Second, + MaxConnections: 512, + Context: nil, + Storage: &tsdb.ReadyStorage{}, + QueryEngine: nil, + RuleManager: nil, + Notifier: nil, + RoutePrefix: "/", + EnableAdminAPI: true, + TSDB: func() *libtsdb.DB { return db }, + } + + opts.Flags = map[string]string{} + + webHandler := New(nil, opts) + go func() { + err := webHandler.Run(context.Background()) + if err != nil { + panic(fmt.Sprintf("Can't start webhandler error %s", err)) + } + }() + + time.Sleep(5 * time.Second) + + resp, err := http.Get("http://localhost:9095/version") + + testutil.Ok(t, err) + testutil.Equals(t, "1; mode=block", resp.Header.Get("X-XSS-Protection")) + testutil.Equals(t, "nosniff", resp.Header.Get("X-Content-Type-Options")) + testutil.Equals(t, "SAMEORIGIN", resp.Header.Get("X-Frame-Options")) + testutil.Equals(t, "frame-ancestors 'self'", resp.Header.Get("Content-Security-Policy")) + +} + func TestReadyAndHealthy(t *testing.T) { t.Parallel() dbDir, err := ioutil.TempDir("", "tsdb-ready")