fix: Set common security headers by default
This commit is contained in:
parent
69c1276a13
commit
cb71ddf401
|
|
@ -107,6 +107,15 @@ type PrometheusConfig struct {
|
|||
DefaultGoMetrics bool `koanf:"defaultGoMetrics"`
|
||||
}
|
||||
|
||||
// SecurityConfig allows users to fine tune the security related HTTP headers.
|
||||
type SecurityConfig struct {
|
||||
HeaderContentSecurityPolicy bool `koanf:"headerContentSecurityPolicy"`
|
||||
ContentSecurityPolicy string `koanf:"contentSecurityPolicy"`
|
||||
HeaderXContentTypeOptions bool `koanf:"headerXContentTypeOptions"`
|
||||
HeaderXFrameOptions bool `koanf:"headerXFrameOptions"`
|
||||
XFrameOptions string `koanf:"xFrameOptions"`
|
||||
}
|
||||
|
||||
// Config is the global config used through the whole app.
|
||||
type Config struct {
|
||||
UseSingleHTTPFrontend bool `koanf:"useSingleHTTPFrontend"`
|
||||
|
|
@ -160,6 +169,7 @@ type Config struct {
|
|||
InsecureAllowDumpActionMap bool `koanf:"insecureAllowDumpActionMap"`
|
||||
InsecureAllowDumpJwtClaims bool `koanf:"insecureAllowDumpJwtClaims"`
|
||||
Prometheus PrometheusConfig `koanf:"prometheus"`
|
||||
Security SecurityConfig `koanf:"security"`
|
||||
SaveLogs SaveLogsConfig `koanf:"saveLogs"`
|
||||
DefaultIconForActions string `koanf:"defaultIconForActions"`
|
||||
DefaultIconForDirectories string `koanf:"defaultIconForDirectories"`
|
||||
|
|
@ -268,6 +278,11 @@ func DefaultConfigWithBasePort(basePort int) *Config {
|
|||
config.InsecureAllowDumpJwtClaims = false
|
||||
config.Prometheus.Enabled = false
|
||||
config.Prometheus.DefaultGoMetrics = false
|
||||
config.Security.HeaderContentSecurityPolicy = true
|
||||
config.Security.ContentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'"
|
||||
config.Security.HeaderXContentTypeOptions = true
|
||||
config.Security.HeaderXFrameOptions = true
|
||||
config.Security.XFrameOptions = "DENY"
|
||||
config.DefaultIconForActions = "😀"
|
||||
config.DefaultIconForDirectories = "📁"
|
||||
config.DefaultIconForBack = "«"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ func (cfg *Config) Sanitize() {
|
|||
cfg.sanitizeAuthRequireGuestsToLogin()
|
||||
cfg.sanitizeLogHistoryPageSize()
|
||||
cfg.sanitizeLocalUserPasswords()
|
||||
cfg.sanitizeSecurityHeaders()
|
||||
|
||||
// log.Infof("cfg %p", cfg)
|
||||
|
||||
|
|
@ -183,6 +184,25 @@ func (cfg *Config) sanitizeLocalUserPasswords() {
|
|||
}
|
||||
}
|
||||
|
||||
func (cfg *Config) sanitizeSecurityHeaders() {
|
||||
cfg.sanitizeSecurityHeadersCSP()
|
||||
cfg.sanitizeSecurityHeadersXFrameOptions()
|
||||
}
|
||||
|
||||
func (cfg *Config) sanitizeSecurityHeadersCSP() {
|
||||
if !cfg.Security.HeaderContentSecurityPolicy || cfg.Security.ContentSecurityPolicy != "" {
|
||||
return
|
||||
}
|
||||
cfg.Security.ContentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'"
|
||||
}
|
||||
|
||||
func (cfg *Config) sanitizeSecurityHeadersXFrameOptions() {
|
||||
if !cfg.Security.HeaderXFrameOptions || cfg.Security.XFrameOptions != "" {
|
||||
return
|
||||
}
|
||||
cfg.Security.XFrameOptions = "DENY"
|
||||
}
|
||||
|
||||
// parsePasswordTemplate expands {{ .Env.VAR }} in local user password fields using the process environment.
|
||||
func parsePasswordTemplate(source string) string {
|
||||
t, err := template.New("password").Option("missingkey=error").Parse(source)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,40 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func applySecurityHeaders(cfg *config.Config, w http.ResponseWriter) {
|
||||
applyCSP(cfg, w)
|
||||
applyXContentTypeOptions(cfg, w)
|
||||
applyXFrameOptions(cfg, w)
|
||||
}
|
||||
|
||||
func applyCSP(cfg *config.Config, w http.ResponseWriter) {
|
||||
if !cfg.Security.HeaderContentSecurityPolicy || cfg.Security.ContentSecurityPolicy == "" {
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Security-Policy", cfg.Security.ContentSecurityPolicy)
|
||||
}
|
||||
|
||||
func applyXContentTypeOptions(cfg *config.Config, w http.ResponseWriter) {
|
||||
if !cfg.Security.HeaderXContentTypeOptions {
|
||||
return
|
||||
}
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
}
|
||||
|
||||
func applyXFrameOptions(cfg *config.Config, w http.ResponseWriter) {
|
||||
if !cfg.Security.HeaderXFrameOptions || cfg.Security.XFrameOptions == "" {
|
||||
return
|
||||
}
|
||||
w.Header().Set("X-Frame-Options", cfg.Security.XFrameOptions)
|
||||
}
|
||||
|
||||
func securityHeadersMiddleware(cfg *config.Config, next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
applySecurityHeaders(cfg, w)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func logDebugRequest(cfg *config.Config, source string, r *http.Request) {
|
||||
if cfg.LogDebugOptions.SingleFrontendRequests {
|
||||
log.Debugf("SingleFrontend HTTP Req URL %v: %q", source, r.URL)
|
||||
|
|
@ -96,7 +130,7 @@ func StartFrontendMux(cfg *config.Config, ex *executor.Executor) {
|
|||
|
||||
srv := &http.Server{
|
||||
Addr: cfg.ListenAddressSingleHTTPFrontend,
|
||||
Handler: mux,
|
||||
Handler: securityHeadersMiddleware(cfg, mux),
|
||||
}
|
||||
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
|
|
|
|||
Loading…
Reference in New Issue