Blog

Web Security articles

HTTP Security Headers Every Website Should Have

The HTTP security headers every site should send, with recommended values, Nginx and Apache examples, and which old headers to drop.

4 min read Web Security

Every time a server sends a page, it also sends invisible instructions called response headers. A handful of them, known as HTTP security headers, tell the browser to switch on protections it would not use by default: refusing to load the site over plain HTTP, blocking your pages from being framed by other sites, and limiting what scripts can do. They cost nothing, take minutes to add, and close off several common attack techniques.

See what your site sends today

Start by checking your current headers. Our HTTP header checker shows the full response from any URL. From a terminal you can use:

curl -sI https://example.com

The -I flag fetches headers only. Note which of the headers below are missing, then add them one at a time.

The essential HTTP security headers

Strict-Transport-Security (HSTS)

Strict-Transport-Security: max-age=31536000; includeSubDomains

Tells the browser to use HTTPS for your domain for the next year (31,536,000 seconds), even if someone types http:// or clicks an old link. This stops attackers on public Wi-Fi from intercepting that first unencrypted request. Only send it once every page and subdomain works over HTTPS with a valid certificate (an SSL checker confirms this quickly), and start with a short max-age if you are unsure.

Content-Security-Policy (CSP)

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

Lists the sources from which the browser may load scripts, styles, images and other resources. A well-built policy is one of the strongest defences against cross-site scripting (XSS), where an attacker gets their JavaScript to run on your page. CSP is the most powerful header here and also the easiest to break a site with, so roll it out in report-only mode first using Content-Security-Policy-Report-Only.

X-Content-Type-Options

X-Content-Type-Options: nosniff

Stops browsers from "sniffing" a file and deciding it is a different type from what the server declared. Without it, a file uploaded as an image could, in some situations, be treated as a script. There is only one valid value, and it is safe to add everywhere.

Clickjacking protection: frame-ancestors or X-Frame-Options

X-Frame-Options: SAMEORIGIN

Clickjacking is when another site loads yours in an invisible frame and tricks users into clicking buttons they cannot see. The modern control is the CSP directive frame-ancestors; X-Frame-Options is the older header that does the same job. Sending both is harmless and covers older browsers. Use DENY if your pages never need to be framed, or SAMEORIGIN if your own site frames them.

Referrer-Policy

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

When a visitor clicks a link to another site, the browser can send the full URL they came from. That URL may contain search terms, account IDs or reset tokens. This value sends the full URL within your own site, only the domain to other HTTPS sites, and nothing when moving from HTTPS to HTTP. It is a sensible default for most businesses.

Permissions-Policy

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

Switches off powerful browser features your site does not use. Empty parentheses mean "no one, not even this site". If a malicious script is ever injected, it cannot quietly request the camera or location. Adjust the list to match what your site genuinely needs.

Headers to remove or stop using

  • X-XSS-Protection: controlled an old browser XSS filter that modern browsers have removed, and the filter itself could introduce problems. Omit it or set it to 0; rely on CSP instead.
  • Public-Key-Pins (HPKP) and Expect-CT: both are obsolete and no longer supported by major browsers.
  • Server and X-Powered-By version details: lines like Server: Apache/2.4.41 (Ubuntu) or X-Powered-By: PHP/8.1.2 help attackers target known vulnerabilities. Hiding them is not a substitute for patching, but there is no reason to advertise. In Nginx use server_tokens off;, in Apache ServerTokens Prod and ServerSignature Off, and in PHP set expose_php = Off.

Adding the headers

Nginx

add_header Strict-Transport-Security "max-age=31536000; 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;

The always parameter makes Nginx send the header on error pages too. Watch out for one Nginx quirk: if a location block has any add_header of its own, it does not inherit those from the parent server block.

Apache

Header always set Strict-Transport-Security "max-age=31536000; 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"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"

This requires mod_headers (sudo a2enmod headers on Debian and Ubuntu).

If your site runs behind a CDN, many CDNs let you add response headers in their dashboard, which is handy when you cannot edit the origin server.

Rolling out safely

  1. Add the low-risk headers first: X-Content-Type-Options, Referrer-Policy and the framing header.
  2. Add HSTS with a short max-age such as 300, confirm nothing breaks, then increase it.
  3. Build CSP in report-only mode, fix what it reports, then enforce it.
  4. Re-test after each change and after every major site update.

For full reference documentation on each header, MDN's HTTP headers reference is reliable and up to date.

Key takeaways

  • Security headers turn on browser protections against downgrade, clickjacking, MIME sniffing and XSS.
  • The core set is HSTS, CSP, X-Content-Type-Options, frame protection, Referrer-Policy and Permissions-Policy.
  • Drop X-XSS-Protection, HPKP and Expect-CT, and hide server version strings.
  • Introduce HSTS and CSP gradually; they are powerful enough to break things if rushed.

Need help with this?

Netifi helps businesses around the world with Web Security. Tell us what you are working on.