diff --git a/pkg/app/app.go b/pkg/app/app.go index 293e30e..5e70541 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -76,6 +76,7 @@ func New(cfg *config.Config) http.Handler { func handle(cfg *config.Config, handlers ...func(http.Handler) http.Handler) http.Handler { handlers = slices.Insert(handlers, 0, middleware.NewSetClientIP(cfg.TrustedProxyPrefixes)) + handlers = slices.Insert(handlers, 0, middleware.SecurityHeaders) if cfg.Debug { handlers = slices.Insert(handlers, 0, middleware.LogDebug) } diff --git a/pkg/middleware/securityheaders.go b/pkg/middleware/securityheaders.go new file mode 100644 index 0000000..a816241 --- /dev/null +++ b/pkg/middleware/securityheaders.go @@ -0,0 +1,14 @@ +package middleware + +import "net/http" + +func SecurityHeaders(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("X-Frame-Options", "DENY") + h.Set("Content-Security-Policy", "default-src 'none'") + h.Set("Cache-Control", "no-store") + next.ServeHTTP(w, r) + }) +} diff --git a/pkg/middleware/securityheaders_test.go b/pkg/middleware/securityheaders_test.go new file mode 100644 index 0000000..b822883 --- /dev/null +++ b/pkg/middleware/securityheaders_test.go @@ -0,0 +1,27 @@ +package middleware_test + +import ( + "net/http" + "net/http/httptest" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/0xfelix/hetzner-dnsapi-proxy/pkg/middleware" +) + +var _ = Describe("SecurityHeaders", func() { + It("sets security headers on the response", func() { + handler := middleware.SecurityHeaders(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + })) + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", http.NoBody)) + + Expect(rec.Code).To(Equal(http.StatusOK)) + Expect(rec.Header().Get("X-Content-Type-Options")).To(Equal("nosniff")) + Expect(rec.Header().Get("X-Frame-Options")).To(Equal("DENY")) + Expect(rec.Header().Get("Content-Security-Policy")).To(Equal("default-src 'none'")) + Expect(rec.Header().Get("Cache-Control")).To(Equal("no-store")) + }) +})