๐ก๏ธ Security Headers and Reference Configurations
Intro: Teams often know that headers matter, but they still ship weak defaults because nobody owns the exact production configuration. This page turns header policy into a practical review artifact instead of a generic recommendation.
What this page includes
- the minimum header set for high-value web applications
- examples for reverse proxies and frameworks
- how to phase in CSP without breaking releases
- how to test and audit the live result
High-value headers to standardize
| Header | Why it matters | Common mistake |
|---|---|---|
Content-Security-Policy |
Limits script and frame abuse | broad wildcards or permanent report-only mode |
X-Content-Type-Options: nosniff |
Reduces content-type confusion | omitted on file and static asset paths |
Referrer-Policy |
Limits leakage of sensitive URLs | too-permissive referral from auth and admin pages |
Permissions-Policy |
Restricts powerful browser features | copy-paste policy with no feature inventory |
Strict-Transport-Security |
Enforces HTTPS | set without understanding preload or subdomain effect |
Cache-Control |
Prevents private data leakage in shared paths | personalized responses cached too broadly |
Cross-Origin-Resource-Policy / related cross-origin headers |
Tightens asset isolation when appropriate | enabled without testing integration impact |
Reference header baseline
Use the following as a starting point, not a universal copy-paste:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RUNTIME_NONCE}' 'strict-dynamic'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; connect-src 'self' https://api.example.com; report-to default-endpoint
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Strict-Transport-Security: max-age=31536000; includeSubDomains
Cache-Control: no-store
When to adjust the baseline
frame-ancestors 'none'may need to change for embedded products or partner dashboards.Cache-Control: no-storeis best for highly sensitive personalized responses, but not for every static asset.style-src 'unsafe-inline'is often transitional; do not leave it in place by habit.connect-srcshould be narrowed to the real API, telemetry, and partner endpoints the page needs.
Apache and Nginx placement
For production work, decide where the header policy lives before you start debating exact values:
- edge/CDN level for global defaults and static assets;
- reverse proxy or web server for host- and route-specific policy;
- application layer only when the app must emit per-request values such as CSP nonces.
A useful rule is: put the control as far outward as you can, but no farther than the point where it still has the data it needs.
What scanners usually mean
Tools such as Skipfish and w3af often flag missing HSTS, missing CSP, absent nosniff, weak frame controls, or CORS inconsistencies. Those findings are useful as a route-discovery prompt, but they still need context:
- is the route authenticated?
- is the content active or inert?
- is the origin sensitive, administrative, or public-only?
- is the scanner finding on a CDN path, the main app, or a legacy subdomain?
Reverse-proxy example
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-$request_id'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Reviewer note: do not assume a reverse-proxy snippet is sufficient until you confirm the application actually emits the right nonce, varies cache correctly, and does not override headers downstream.
How to phase in CSP
A practical rollout sequence is:
- inventory scripts, frames, telemetry, and inline script requirements;
- ship report-only mode for a short, bounded period;
- fix the top noisy violations and remove dead origins;
- enforce on high-value pages first;
- move from origin allowlists toward nonce-based or stronger script strategy where practical.
Test commands
curl -I https://app.example.com/
curl -I https://app.example.com/account/settings
curl -I https://app.example.com/admin
Use a browser developer console and automated smoke tests to confirm that:
- the same route class receives the same expected headers;
- personalized pages are not cached incorrectly;
- CSP is present on login, account, billing, and admin pages;
- upload and download paths do not accidentally drop header policy.
Common production mistakes
- different header policies on CDN, edge, and origin paths;
- CSP enabled only on the marketing site, not the product itself;
- frame protections missing from legacy admin tools;
- file-download endpoints serving active content inline;
no-storeforgotten on sensitive API-backed SSR responses.
Related pages
- Frontend Security Review Playbook
- File Upload, Download, and Browser Rendering Risks
- snippets/frontend/security-headers-examples.md
- Web-Server Security Controls: HTTPS, CORS, CSP, and HSTS for Apache and Nginx
Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.