DEV Community

Cover image for 6 HTTP Security Headers Your Site Is Probably Missing (and how to fix each one)
Jeff W
Jeff W

Posted on

6 HTTP Security Headers Your Site Is Probably Missing (and how to fix each one)

Run any random production site through a headers check and odds are it's missing at least half of the headers below. Not because anyone decided against them — usually because nobody ever added them in the first place. They cost nothing, take one line to set, and most frameworks don't set them for you by default.

Here's what each one actually does, and the one-liner to add it in a few common stacks.

1. Strict-Transport-Security (HSTS)

Tells the browser "never connect to this site over plain HTTP again, even if someone types http:// or links to it that way." Without it, every visit is one stray link or bookmark away from a downgrade-to-HTTP attack.

Strict-Transport-Security: max-age=63072000; includeSubDomains
Enter fullscreen mode Exit fullscreen mode

Express (helmet):

app.use(helmet.hsts({ maxAge: 63072000, includeSubDomains: true }));
Enter fullscreen mode Exit fullscreen mode

nginx:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
Enter fullscreen mode Exit fullscreen mode

2. Content-Security-Policy (CSP)

The single biggest lever against XSS. It tells the browser exactly which origins are allowed to supply scripts, styles, images, etc. — so even if an attacker manages to inject a <script> tag somewhere, the browser refuses to run it if it's not from an allowed source.

It's also the one people avoid because a bad policy breaks your own site. Start narrow and loosen it as you find real violations (report-only mode is your friend here):

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com
Enter fullscreen mode Exit fullscreen mode

3. X-Frame-Options

Stops your pages from being loaded inside a hidden <iframe> on someone else's site — the setup behind clickjacking ("click here to win a prize" that's secretly your bank's transfer-confirmation button underneath).

X-Frame-Options: DENY
Enter fullscreen mode Exit fullscreen mode

(CSP's frame-ancestors directive supersedes this in modern browsers, but set both — older clients don't understand frame-ancestors.)

4. X-Content-Type-Options

One value, always the same:

X-Content-Type-Options: nosniff
Enter fullscreen mode Exit fullscreen mode

Without it, some browsers will "sniff" a response's actual content and decide to treat it as something other than what the Content-Type header says — the classic version being an uploaded file that's technically an image but gets executed as script.

5. Referrer-Policy

Controls how much of your own URL — including query strings, which sometimes contain tokens or IDs you didn't mean to share — gets sent to whatever site a visitor clicks away to.

Referrer-Policy: strict-origin-when-cross-origin
Enter fullscreen mode Exit fullscreen mode

A reasonable default: full URL on same-origin navigation, just the origin (no path/query) on cross-origin ones.

6. Permissions-Policy

Explicitly turns off browser features your site never uses — camera, microphone, geolocation, USB, etc. Even if you never call these APIs yourself, a compromised third-party script embedded on your page could try to.

Permissions-Policy: camera=(), microphone=(), geolocation=()
Enter fullscreen mode Exit fullscreen mode

Bonus: stop announcing your stack

Server: nginx/1.18.0 and X-Powered-By: Express don't do anything for your visitors — they just hand an attacker a head start on which known vulnerabilities to try first.

server_tokens off;
Enter fullscreen mode Exit fullscreen mode
app.disable('x-powered-by'); // Express
Enter fullscreen mode Exit fullscreen mode

Checking your own site

Reading headers off a raw response is annoying to do by hand every time — curl -I and then squinting for six specific header names. I built a small free tool that just does the check and tells you what's missing and why each one matters:

Security Headers Checker — no signup, doesn't store anything you enter, checks all six headers above plus flags the Server/X-Powered-By leaks.

(Disclosure: I built this — it's a free tool from ShieldIngress, a WAF/edge security product I run. The checker itself has no paywall or catch, I'd genuinely rather more sites just have these headers set.)

If you run it against your own site and find gaps, the snippets above should cover fixing most of them in a few minutes.

Top comments (0)