API middleware: - SecurityHeaders now sets Content-Security-Policy from config/security.php - Default API policy: "default-src 'none'; frame-ancestors 'none'" - Supports report-only mode via CSP_REPORT_ONLY env var - Policy value configurable via CSP_POLICY env var Nginx deployment configs (deploy/nginx/): - security-headers.conf: shared headers for all server blocks - csp-api.conf: restrictive JSON-only policy for api.crewli.app - csp-spa.conf: SPA policy for app/admin (self + unsafe-inline styles) - csp-portal.conf: portal policy matching SPA Development: - CSP meta tags added to all three index.html files - Includes 'unsafe-inline' + 'unsafe-eval' for Vite HMR/loader script - Each app allows its own ws:// port for HMR websocket Resolves security finding A13-9. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
20 lines
875 B
Plaintext
20 lines
875 B
Plaintext
# ============================================================
|
|
# Crewli Security Headers — Nginx Configuration
|
|
# ============================================================
|
|
# Include this file in each server block:
|
|
# include /path/to/deploy/nginx/security-headers.conf;
|
|
#
|
|
# Three separate CSP policies for API vs SPA vs Portal.
|
|
# Adjust connect-src if the API domain changes.
|
|
# ============================================================
|
|
|
|
# --- Shared headers (all server blocks) ---
|
|
|
|
add_header X-Content-Type-Options "nosniff" always;
|
|
add_header X-Frame-Options "DENY" always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
|
|
|
# HSTS: enable after confirming HTTPS works correctly
|
|
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|