← All guides Web · Security headers

HTTP security headers explained

The response headers that force HTTPS, block injected scripts and stop clickjacking — and how to add them to Nginx, Apache or Caddy.

In short: security headers are small instructions your server sends with every page that tell the browser how to behave more safely. Adding six of them — HSTS, Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Referrer-Policy and Permissions-Policy — closes off some of the most common web attacks, often in a few lines of server config.

What are HTTP security headers?

Every time someone opens a page on your site, your server sends back the page and a set of HTTP response headers — metadata the browser reads before it renders anything. Security headers are a subset of those: directives that tell the browser to enforce HTTPS, refuse to run untrusted scripts, or stop your pages being embedded in someone else's site. They cost nothing to serve, work in every modern browser, and are one of the highest-impact, lowest-effort improvements you can make. CyberScore checks six of them.

Strict-Transport-Security (HSTS)

HSTS tells the browser: "from now on, only ever talk to this domain over HTTPS." Once a browser has seen the header, it refuses plain-HTTP connections automatically, which defeats downgrade and man-in-the-middle attacks that rely on that first insecure request.

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

max-age is in seconds (two years above). Add includeSubDomains only when every subdomain is HTTPS-ready, and preload if you intend to submit your domain to the browser preload list.

Only send HSTS over HTTPS, and be sure HTTPS works everywhere first — once a browser caches a long max-age, you cannot easily undo it if something is still on HTTP.

Content-Security-Policy (CSP)

CSP is the most powerful — and most fiddly — header. It lists exactly which sources of scripts, styles, images and so on the browser is allowed to load, which is the single best defence against cross-site scripting (XSS). A strict starting point:

Content-Security-Policy: default-src 'self'; img-src 'self' data:; object-src 'none'; frame-ancestors 'self'; base-uri 'self'

Because a too-strict policy can break a working site, roll it out in report-only mode first and watch what it would have blocked:

Content-Security-Policy-Report-Only: default-src 'self'

Tighten it until nothing legitimate is reported, then switch to the enforcing header. Avoid 'unsafe-inline' for scripts where you can — it removes most of CSP's protection.

X-Content-Type-Options

One fixed value stops browsers from "sniffing" a file's type and, for example, running an uploaded image as JavaScript:

X-Content-Type-Options: nosniff

X-Frame-Options

This stops other sites embedding your pages in an <iframe> to trick users into clicking hidden buttons (clickjacking):

X-Frame-Options: SAMEORIGIN

The modern equivalent is CSP's frame-ancestors 'self'; sending both covers older and newer browsers.

Referrer-Policy

Controls how much of the current URL is shared when a user clicks a link to another site — important if your URLs contain tokens or private paths. A good balanced default:

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

Permissions-Policy

Lets you switch off browser features your site does not use — camera, microphone, geolocation — so a compromised script cannot silently request them:

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

How to add them to your server

Nginx

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Apache (.htaccess or vhost)

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"

Caddy

header {
    Strict-Transport-Security "max-age=63072000; includeSubDomains"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "SAMEORIGIN"
    Referrer-Policy "strict-origin-when-cross-origin"
}

Common mistakes

Check your own headers

Run your domain through CyberScore and you will see, in seconds, which of these six headers are present, which are missing, and a prioritised plan to fix the gaps — plus a downloadable PDF report.

Scan your website free →