diff --git a/config.template.yml b/config.template.yml
index e94f8ae16..44820d343 100644
--- a/config.template.yml
+++ b/config.template.yml
@@ -71,6 +71,12 @@ server:
## The path to the DER base64/PEM format public certificate.
certificate: ""
+ ## Server headers configuration/customization.
+ headers:
+
+ ## The CSP Template. Read the docs.
+ csp_template: ""
+
##
## Log Configuration
##
diff --git a/docs/configuration/server.md b/docs/configuration/server.md
index ba8cc8d5d..a724cc384 100644
--- a/docs/configuration/server.md
+++ b/docs/configuration/server.md
@@ -24,6 +24,8 @@ server:
tls:
key: ""
certificate: ""
+ headers:
+ csp_template: ""
```
## Options
@@ -209,6 +211,25 @@ required: situational
The path to the public certificate for TLS connections. Must be in DER base64/PEM format.
+
+### headers
+
+#### csp_template
+
+type: string
+{: .label .label-config .label-purple }
+default: ""
+{: .label .label-config .label-blue }
+required: no
+{: .label .label-config .label-green }
+
+
+This customizes the value of the Content-Security-Policy header. It will replace all instances of `${NONCE}` with the
+nonce value of the Authelia react bundle. This is an advanced option to customize and you should do sufficient research
+about how browsers utilize and understand this header before attempting to customize it.
+
+For example, the default CSP template is `default-src 'self'; object-src 'none'; style-src 'self' 'nonce-${NONCE}'`.
+
## Additional Notes
### Buffer Sizes
diff --git a/internal/configuration/config.template.yml b/internal/configuration/config.template.yml
index e94f8ae16..44820d343 100644
--- a/internal/configuration/config.template.yml
+++ b/internal/configuration/config.template.yml
@@ -71,6 +71,12 @@ server:
## The path to the DER base64/PEM format public certificate.
certificate: ""
+ ## Server headers configuration/customization.
+ headers:
+
+ ## The CSP Template. Read the docs.
+ csp_template: ""
+
##
## Log Configuration
##
diff --git a/internal/configuration/schema/server.go b/internal/configuration/schema/server.go
index b05c448f8..e1d6f850d 100644
--- a/internal/configuration/schema/server.go
+++ b/internal/configuration/schema/server.go
@@ -12,7 +12,8 @@ type ServerConfiguration struct {
EnableExpvars bool `koanf:"enable_endpoint_expvars"`
DisableHealthcheck bool `koanf:"disable_healthcheck"`
- TLS ServerTLSConfiguration `koanf:"tls"`
+ TLS ServerTLSConfiguration `koanf:"tls"`
+ Headers ServerHeadersConfiguration `koanf:"headers"`
}
// ServerTLSConfiguration represents the configuration of the http servers TLS options.
@@ -21,6 +22,11 @@ type ServerTLSConfiguration struct {
Key string `koanf:"key"`
}
+// ServerHeadersConfiguration represents the customization of the http server headers.
+type ServerHeadersConfiguration struct {
+ CSPTemplate string `koanf:"csp_template"`
+}
+
// DefaultServerConfiguration represents the default values of the ServerConfiguration.
var DefaultServerConfiguration = ServerConfiguration{
Host: "0.0.0.0",
diff --git a/internal/configuration/validator/const.go b/internal/configuration/validator/const.go
index ab0a04f98..487c58e44 100644
--- a/internal/configuration/validator/const.go
+++ b/internal/configuration/validator/const.go
@@ -171,6 +171,7 @@ var ValidKeys = []string{
"server.disable_healthcheck",
"server.tls.key",
"server.tls.certificate",
+ "server.headers.csp_template",
// TOTP Keys.
"totp.issuer",
diff --git a/internal/server/const.go b/internal/server/const.go
index ed3484db9..610b2953e 100644
--- a/internal/server/const.go
+++ b/internal/server/const.go
@@ -23,3 +23,9 @@ X_AUTHELIA_HEALTHCHECK_HOST=%s
X_AUTHELIA_HEALTHCHECK_PORT=%d
X_AUTHELIA_HEALTHCHECK_PATH=%s
`
+
+const (
+ cspDefaultTemplate = "default-src 'self'; object-src 'none'; style-src 'self' 'nonce-%s'"
+ cspDefaultDevTemplate = "default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'"
+ cspNoncePlaceholder = "${NONCE}"
+)
diff --git a/internal/server/template.go b/internal/server/template.go
index e3214aca1..c3bab9fe9 100644
--- a/internal/server/template.go
+++ b/internal/server/template.go
@@ -5,6 +5,7 @@ import (
"io"
"os"
"path/filepath"
+ "strings"
"text/template"
"github.com/authelia/authelia/v4/internal/logging"
@@ -71,11 +72,13 @@ func ServeTemplatedFile(publicDir, file, assetPath, duoSelfEnrollment, rememberM
switch {
case publicDir == swaggerAssets:
- ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("base-uri 'self' ; default-src 'self' ; img-src 'self' https://validator.swagger.io data: ; object-src 'none' ; script-src 'self' 'unsafe-inline' 'nonce-%s' ; style-src 'self' 'nonce-%s'", nonce, nonce))
+ ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("base-uri 'self'; default-src 'self'; img-src 'self' https://validator.swagger.io data:; object-src 'none'; script-src 'self' 'unsafe-inline' 'nonce-%s'; style-src 'self' 'nonce-%s'", nonce, nonce))
+ case ctx.Configuration.Server.Headers.CSPTemplate != "":
+ ctx.Response.Header.Add("Content-Security-Policy", strings.ReplaceAll(ctx.Configuration.Server.Headers.CSPTemplate, cspNoncePlaceholder, nonce))
case os.Getenv("ENVIRONMENT") == dev:
- ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
+ ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf(cspDefaultDevTemplate, nonce))
default:
- ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' ; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
+ ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf(cspDefaultTemplate, nonce))
}
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ Base, BaseURL, CSPNonce, DuoSelfEnrollment, LogoOverride, RememberMe, ResetPassword, Session, Theme string }{Base: base, BaseURL: baseURL, CSPNonce: nonce, DuoSelfEnrollment: duoSelfEnrollment, LogoOverride: logoOverride, RememberMe: rememberMe, ResetPassword: resetPassword, Session: session, Theme: theme})