From 491ade8fe4cd564e5e7e975bc15d64dbfa40721a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Krzy=C5=BCanowski?= Date: Tue, 24 Feb 2026 21:52:49 +0100 Subject: [PATCH] feat: Add `strict-headers` and `relaxed-headers` middleware for enhanced security flexibility - Replaced `security-headers` middleware in `docker-compose.yml` with `strict-headers` and `relaxed-headers` where applicable. - Updated `INTEGRATION_GUIDE.md` with details on both middleware types, highlighting their respective Content-Security-Policy configurations. - Added `strict-headers` and `relaxed-headers` definitions to `config/dynamic.yml` for improved CSP customization. --- config/dynamic.yml | 11 ++++++++++- docker-compose.yml | 8 ++++---- docs/INTEGRATION_GUIDE.md | 20 ++++++++++++-------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/config/dynamic.yml b/config/dynamic.yml index b5819ec..64ac879 100644 --- a/config/dynamic.yml +++ b/config/dynamic.yml @@ -8,7 +8,7 @@ tls: http: middlewares: - security-headers: + strict-headers: headers: customResponseHeaders: X-Frame-Options: "DENY" @@ -17,3 +17,12 @@ http: X-XSS-Protection: "0" Strict-Transport-Security: "max-age=31536000; includeSubDomains" Content-Security-Policy: "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self'" + relaxed-headers: + headers: + customResponseHeaders: + X-Frame-Options: "DENY" + X-Content-Type-Options: "nosniff" + Referrer-Policy: "strict-origin-when-cross-origin" + X-XSS-Protection: "0" + Strict-Transport-Security: "max-age=31536000; includeSubDomains" + Content-Security-Policy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self'" diff --git a/docker-compose.yml b/docker-compose.yml index 500675a..7238424 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -46,7 +46,7 @@ services: - "traefik.http.routers.dashboard.rule=Host(`traefik.docker.localhost`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.tls=true" - - "traefik.http.routers.dashboard.middlewares=security-headers@file" + - "traefik.http.routers.dashboard.middlewares=relaxed-headers@file" redis: image: redis:8.6.1-alpine @@ -131,7 +131,7 @@ services: - "traefik.enable=true" - "traefik.http.routers.pma.rule=Host(`pma.docker.localhost`)" - "traefik.http.routers.pma.tls=true" - - "traefik.http.routers.pma.middlewares=security-headers@file" + - "traefik.http.routers.pma.middlewares=strict-headers@file" pgadmin: image: dpage/pgadmin4:9.12.0 @@ -160,7 +160,7 @@ services: - "traefik.enable=true" - "traefik.http.routers.pgadmin.rule=Host(`pgadmin.docker.localhost`)" - "traefik.http.routers.pgadmin.tls=true" - - "traefik.http.routers.pgadmin.middlewares=security-headers@file" + - "traefik.http.routers.pgadmin.middlewares=strict-headers@file" mailpit: image: axllent/mailpit:v1.29.1 @@ -183,7 +183,7 @@ services: - "traefik.enable=true" - "traefik.http.routers.mailpit.rule=Host(`mailpit.docker.localhost`)" - "traefik.http.routers.mailpit.tls=true" - - "traefik.http.routers.mailpit.middlewares=security-headers@file" + - "traefik.http.routers.mailpit.middlewares=strict-headers@file" - "traefik.http.services.mailpit.loadbalancer.server.port=8025" volumes: diff --git a/docs/INTEGRATION_GUIDE.md b/docs/INTEGRATION_GUIDE.md index 71b3afb..4336850 100644 --- a/docs/INTEGRATION_GUIDE.md +++ b/docs/INTEGRATION_GUIDE.md @@ -5230,9 +5230,12 @@ pre-configured security headers middleware to protect against common web vulnera #### Security Headers Middleware -The proxy includes a **security headers middleware** (`security-headers`) that automatically applies essential security -headers to HTTP responses. These headers protect against common attacks like clickjacking, MIME-type sniffing, and -protocol downgrade attacks. +The proxy includes two **security headers middlewares**: + +- **`strict-headers`** — full CSP without `unsafe-inline`; use this for your own services +- **`relaxed-headers`** — relaxed CSP with `unsafe-inline` allowed; used internally by the Traefik dashboard which requires inline scripts and styles + +Both apply the same security headers (HSTS, X-Frame-Options, etc.) and differ only in the `Content-Security-Policy` directive. **Included Headers:** @@ -5259,8 +5262,8 @@ services: - "traefik.enable=true" - "traefik.http.routers.app.rule=Host(`app.docker.localhost`)" - "traefik.http.routers.app.tls=true" - # Apply security headers middleware - - "traefik.http.routers.app.middlewares=security-headers@file" + # Apply strict security headers middleware + - "traefik.http.routers.app.middlewares=strict-headers@file" networks: traefik-proxy: @@ -5270,9 +5273,10 @@ networks: **Key Points:** - The `@file` suffix tells Traefik to use middleware defined in the dynamic configuration file (`config/dynamic.yml`) -- Security headers are applied automatically to the Traefik dashboard +- The Traefik dashboard uses `relaxed-headers@file` (allows `unsafe-inline` required by its Vue.js frontend) +- Use `strict-headers@file` for your own services — it enforces a strict CSP without `unsafe-inline` - You can chain multiple middlewares by separating them with commas: - `middlewares=security-headers@file,other-middleware` + `middlewares=strict-headers@file,other-middleware` - The CSP includes `object-src 'none'` (prevents plugin embedding like Flash) and `base-uri 'self'` (prevents base URL hijacking attacks) **Verification:** @@ -5333,7 +5337,7 @@ networks: 3. **Combine security headers with other middleware:** ```yaml - - "traefik.http.routers.app.middlewares=security-headers@file,compress,ratelimit" + - "traefik.http.routers.app.middlewares=strict-headers@file,compress,ratelimit" ``` **For More Information:**