What it is#
HTTP response headers tell browsers how to handle scripts, framing, transport, MIME types, referrers, and browser capabilities. When these policies are missing, the browser applies defaults that may be broader than the application intends.
Security headers are defense in depth. A Content Security Policy can reduce the impact of some script injection, but it does not make unsafe output handling acceptable. Frame restrictions reduce clickjacking, but they do not replace authorization and confirmation for sensitive actions.
The correct policy depends on the application. Copying a generic header set without testing can either break functionality or create a policy so permissive that it provides little protection.
Why it matters#
- Increase the likelihood or impact of cross-site scripting.
- Allow application pages to be framed for clickjacking.
- Permit MIME sniffing to reinterpret uploaded or generated content.
- Leak full URLs or sensitive path information through the
Refererheader. - Allow browsers to use powerful features that the application does not need.
- Permit insecure HTTP use when HSTS is absent or incorrectly scoped.
Usually low to medium when reported alone. High when a missing policy directly exposes sensitive actions, active uploaded content, or a known injection path. Actual severity depends on context: who is affected, what data or actions are reachable, and existing controls.
Examples#
# Vulnerable: no explicit browser security policy.
server {
listen 443 ssl;
server_name portal.example.com;
location / { proxy_pass http://portal; }
}
# Fixed: an application-specific baseline.
server {
listen 443 ssl;
server_name portal.example.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'" 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 X-Frame-Options "DENY" always;
location / { proxy_pass http://portal; }
}
The CSP must be extended deliberately for required scripts, styles, images, APIs, frames, and workers. Avoid broad wildcards and unsafe inline execution.
How to fix it#
1. Deploy Content Security Policy. Start with Content-Security-Policy-Report-Only, collect violations, then enforce a policy based on nonces or hashes and narrow source lists. Define object-src, base-uri, frame-ancestors, and form-action explicitly.
2. Prevent framing. Use CSP frame-ancestors. Add X-Frame-Options: DENY or SAMEORIGIN for older clients where compatible.
3. Prevent MIME confusion. Send X-Content-Type-Options: nosniff and accurate Content-Type values on every response, especially downloads and user content.
4. Control referrer data. Use Referrer-Policy: strict-origin-when-cross-origin or a stricter policy based on application requirements. Keep secrets out of URLs regardless.
5. Limit browser capabilities. Set a Permissions-Policy that disables camera, microphone, geolocation, payment, USB, and other features unless the application needs them.
6. Enforce HTTPS with HSTS. Add HSTS only after the domain and required subdomains are fully HTTPS-capable. Consider preload separately; it is difficult to reverse quickly.
7. Retire obsolete headers thoughtfully. Do not rely on X-XSS-Protection; modern CSP and safe output encoding are the appropriate controls. Avoid legacy policies that provide a false sense of security.
8. Set headers centrally and test exceptions. Configure the reverse proxy or application middleware, then verify error pages, redirects, static assets, authentication responses, and CDN-served content.
How to test for it#
- Collect headers from normal pages, APIs, errors, redirects, downloads, static files, and authentication flows over HTTPS.
- Compare the effective CSP with actual application dependencies and look for wildcards,
unsafe-inline,unsafe-eval, untrusted script hosts, or missing high-value directives. - Use CSP report-only mode and browser developer tools to identify violations before enforcement.
- Place a non-sensitive test page in a controlled iframe to verify
frame-ancestorsandX-Frame-Optionsbehavior. - Verify uploaded or generated content is served with the intended MIME type and
nosniff. - Check referrer behavior using a controlled destination that records only a harmless test URL.
- Confirm HSTS appears only over HTTPS, has the intended scope, and does not strand required HTTP-only subdomains.
- Add automated response-header tests to CI and synthetic monitoring so proxies or CDN changes do not silently remove policies.
References#
- CWE-693: Protection Mechanism Failure ↗ (opens in a new tab)cwe.mitre.org
- OWASP HTTP Headers Cheat Sheet ↗ (opens in a new tab)cheatsheetseries.owasp.org
- OWASP Content Security Policy Cheat Sheet ↗ (opens in a new tab)cheatsheetseries.owasp.org
- OWASP Top 10 A05:2021 Security Misconfiguration ↗ (opens in a new tab)owasp.org
- MDN: HTTP headers ↗ (opens in a new tab)developer.mozilla.org