Web SecurityOctober 9, 2026•8 min read

Complete Guide to HTTP Security Headers in 2026: CSP, HSTS, X-Frame-Options & Permissions Policy

Deep dive into configuring modern HTTP response headers in Next.js and Nginx. Defend against cross-site scripting (XSS), clickjacking, and MIME sniffing.

RB
Rohit Bhatu — Lead Systems Architect
Complete Guide to HTTP Security Headers in 2026: CSP, HSTS, X-Frame-Options & Permissions Policy

1. The Crucial Role of Defense-in-Depth Headers

Application-layer security starts in the code, but browser enforcement begins with HTTP response headers. Security headers instruct user agents to constrain execution permissions, restrict asset origins, and reject unencrypted transports before JavaScript is executed.

Web security audits and penetration tests frequently flag missing or misconfigured headers as moderate-to-high risk vulnerabilities.

2. Content-Security-Policy (CSP) Demystified

Content-Security-Policy is the single most effective defense against Cross-Site Scripting (XSS) and unauthorized resource injection. By specifying whitelisted origins for scripts, styles, images, and fonts, you disallow malicious scripts injected into DOM nodes from fetching payloads or executing.

A modern, strict CSP disallows `unsafe-inline` scripts by using cryptographic nonces or sha256 hashes generated dynamically per request.

Configuring strict security headers in Next.js middlewaretypescript
import { NextResponse } from "next/server";
import type { NextRequest } from "next/request";

export function middleware(request: NextRequest) {
  const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
  const response = NextResponse.next();

  const cspHeader = `
    default-src 'self';
    script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
    style-src 'self' 'unsafe-inline';
    img-src 'self' blob: data: https:;
    font-src 'self' data:;
    object-src 'none';
    base-uri 'self';
    form-action 'self';
    frame-ancestors 'none';
    upgrade-insecure-requests;
  `.replace(/\s{2,}/g, " ").trim();

  response.headers.set("Content-Security-Policy", cspHeader);
  response.headers.set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
  response.headers.set("X-Frame-Options", "DENY");
  response.headers.set("X-Content-Type-Options", "nosniff");
  response.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
  response.headers.set("Permissions-Policy", "camera=(), microphone=(), geolocation=()");

  return response;
}

3. Enforcing HSTS and Preload Eligibility

HTTP Strict Transport Security (HSTS) informs browsers that a site must only be reached using HTTPS. Without HSTS, a user typing `example.com` makes an initial plaintext HTTP request that attackers can intercept with SSL stripping tools.

Specifying `includeSubDomains` protects wildcard internal hostnames, and adding `preload` allows inclusion in the global Chromium/Firefox HSTS preload list hardcoded into browser binaries.

Never set the HSTS preload directive on domains that host internal HTTP-only intranet tools, as browsers will permanently refuse plaintext connections.

4. Validating Your Live Configuration

Deploying headers without real-world validation can break external embeds, web fonts, or analytics endpoints. Use an automated scanner such as our Website Health Checker to verify status codes, TLS certificates, and header compliance before rolling out to production traffic.