Modern browsers ship with powerful defenses, but many of them stay switched off until your server asks for them. That request happens through HTTP response headers. A few lines of configuration can neutralize entire attack classes, including many XSS and clickjacking attempts you studied earlier. In this lesson you'll learn the headers that matter in 2026, what each one protects against, and how to roll them out without breaking your site.
Content-Security-Policy (CSP) tells the browser exactly which sources of scripts, styles, images, and frames are allowed. Even if an attacker manages to inject markup, the browser refuses to run scripts from unapproved origins:
Content-Security-Policy: default-src 'self';
script-src 'self' https://cdn.example.com;
object-src 'none';
frame-ancestors 'none';
base-uri 'self'Key directives: default-src is the fallback for everything, script-src controls JavaScript, object-src 'none' blocks legacy plugins, and frame-ancestors 'none' prevents any site from framing yours, which is the modern clickjacking defense. Avoid unsafe-inline; if you need inline scripts, use nonces that change per response. Deploy safely by starting with Content-Security-Policy-Report-Only, which reports violations without blocking, then enforce once the reports are clean.
HSTS tells the browser to refuse plain HTTP for your domain, defeating downgrade attacks on hostile networks:
Strict-Transport-Security: max-age=31536000; includeSubDomainsAfter the first visit, the browser upgrades every request to HTTPS for a year, even if the user types http:// or clicks an http link.
X-Content-Type-Options: nosniff stops the browser from guessing content types, preventing a disguised upload from executing as script.Referrer-Policy: strict-origin-when-cross-origin sends only your origin, not full URLs with tokens or search terms, to other sites.Permissions-Policy: camera=(), microphone=(), geolocation=() disables powerful APIs your site never uses.X-Frame-Options: DENY is the legacy clickjacking header; keep it alongside frame-ancestors for old browsers.Cookies carry sessions, so their flags are security headers in miniature:
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/Secure restricts the cookie to HTTPS, HttpOnly hides it from JavaScript so stolen-script attacks cannot read it, and SameSite=Lax (or Strict) stops the cookie riding along on cross-site requests, which blunts CSRF.
In an Express application, the helmet middleware applies sensible defaults in one line, and you can customize from there:
import express from 'express'
import helmet from 'helmet'
const app = express()
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
}
}
}))On Nginx you add add_header lines in the server block; most CDNs and platforms like Netlify or Vercel let you declare headers in a config file.
Free scanners such as securityheaders.com and the Mozilla HTTP Observatory grade your headers and explain every missing one. Browser devtools show received headers under the Network tab. Make header checks part of deployment: a one-line CI test that fetches the homepage and asserts CSP and HSTS exist prevents silent regressions.
frame-ancestors and X-Frame-Options stop clickjacking.nosniff, Referrer-Policy, and Permissions-Policy close smaller but real gaps.Secure, HttpOnly, and SameSite protect sessions; audit everything with a scanner in CI.In the final lesson we bring the whole course together: Building a Security Mindset with audits, updates and incident response.