PushBackLog

Security Headers

Soft enforcement Complete by PushBackLog team
Topic: security Skillset: backend Skillset: frontend Skillset: devops Technology: generic Stage: execution Stage: review

Security Headers

Status: Complete
Category: Security
Default enforcement: Soft
Author: PushBackLog team


Tags

  • Topic: security
  • Skillset: backend, frontend, devops
  • Technology: generic
  • Stage: execution, review

Summary

HTTP security headers are server-side declarations that instruct browsers and intermediaries how to handle the content of a response. They provide defence-in-depth against cross-site scripting (XSS), clickjacking, MIME-type sniffing, protocol downgrade attacks, and information leakage. Most can be configured once at the web server or API gateway level and then apply globally. Omitting them is a low-cost, high-impact vulnerability that automated scanners detect and report.


Rationale

Security headers are cheap to deploy and valuable to have

A properly configured Content-Security-Policy header reduces the exploitability of XSS vulnerabilities by restricting which scripts the browser will execute. An X-Frame-Options header prevents clickjacking. Strict-Transport-Security prevents protocol downgrade attacks. These protections do not require application code changes — they are HTTP responses headers that can usually be set at the reverse proxy or CDN level.

Not deploying them is leaving available security controls unused, which OWASP classifies under A02 (Security Misconfiguration).


Guidance

Essential security headers

Content-Security-Policy (CSP)

The most powerful and most complex security header. CSP tells the browser which sources it may load scripts, styles, images, and other resources from. A strict CSP makes XSS attacks significantly harder to exploit.

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{RANDOM_NONCE}';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';

Start with CSP in report-only mode (Content-Security-Policy-Report-Only) to identify violations before enforcing:

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

Strict-Transport-Security (HSTS)

Instructs browsers to only access the site via HTTPS, preventing protocol downgrade attacks:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • max-age=31536000 — 1 year; start with a shorter value and increase once stable
  • includeSubDomains — applies to all subdomains
  • preload — submit to browser preload lists (browsers will refuse HTTP before ever connecting)

X-Frame-Options

Prevents the page from being embedded in an <iframe> (clickjacking protection):

X-Frame-Options: DENY

Use frame-ancestors 'none' in CSP for newer browsers (CSP takes precedence), but keep X-Frame-Options for older browser compatibility.

X-Content-Type-Options

Prevents browsers from MIME-sniffing the response content type:

X-Content-Type-Options: nosniff

Referrer-Policy

Controls how much referrer information is included with requests:

Referrer-Policy: strict-origin-when-cross-origin

Permissions-Policy

Controls which browser features the page can use:

Permissions-Policy: camera=(), microphone=(), geolocation=(self), payment=(self)

Cross-Origin headers

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-site

These isolate the browsing context and protect against Spectre-class side-channel attacks.

Headers to remove (information disclosure)

# Remove these — they leak server implementation details
X-Powered-By: (remove entirely)
Server: (remove or set to a generic value: "Server: web")
X-AspNet-Version: (remove)

Implementation in Node.js (Helmet)

import helmet from 'helmet';

app.use(
  helmet({
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
        styleSrc: ["'self'", "'unsafe-inline'"],
        imgSrc: ["'self'", 'data:', 'https:'],
        connectSrc: ["'self'", process.env.API_URL!],
        frameAncestors: ["'none'"],
        objectSrc: ["'none'"],
      },
    },
    hsts: {
      maxAge: 31536000,
      includeSubDomains: true,
      preload: true,
    },
    referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
  })
);

Verification tools

  • securityheaders.com — grade and full header analysis for any URL
  • Mozilla Observatory — comprehensive security header check
  • OWASP ZAP — automated scan includes header checks
  • Helmet audit in CI: npx helmet-csp-check

Review checklist

  • Content-Security-Policy is present and restricts script sources
  • Strict-Transport-Security is set with a minimum 6-month max-age
  • X-Frame-Options: DENY or frame-ancestors 'none' in CSP is set
  • X-Content-Type-Options: nosniff is set
  • Referrer-Policy is set
  • X-Powered-By and Server headers do not reveal implementation details
  • Headers verified with securityheaders.com or equivalent before production