HTTP security headers: what to set, and why
A handful of response headers and cookie flags close whole classes of attack in the browser. Here is what each one does, a safe value to start from, and which of them TrustSek scores today.
By the TrustSek editorial team · Last reviewed
- Module
- TLS and web hygiene · 20%
- Headers scored
- CSP, HSTS, X-XSS-Protection
- Cookie flags
- Secure, HttpOnly
Security headers are instructions your server sends with each response, telling the browser how to treat the page. They cost almost nothing to add, and they limit the damage from problems you have not found yet: an injected script, a page framed by another site, a cookie sent over the wrong connection.
This guide covers the headers worth setting on any website, a sensible value to start from, and what an outside-in scan can and cannot see. Test every change on a staging site first. A strict header set carelessly can break a page as surely as an attack.
The examples use example.com. Replace it with your own domain.
Where headers come from
Headers can be set in the application, in the web server, in a load balancer or at a CDN. Pick one layer and set them there, so they are not duplicated or overwritten. Check what a page actually returns:
curl -sI https://example.com/
Headers apply per response. A header set on the home page does not cover a login page served by another application, an API on a subdomain or a file served from a storage bucket. Check the pages that matter, not only the front page.
Content-Security-Policy
Content Security Policy (CSP Level 3) tells the browser which sources of script, style, images, frames and connections are legitimate for the page. Its main value is against cross-site scripting: even if an attacker manages to inject a script, a strict policy stops the browser from running it.
A policy has to fit the site, so introduce it in report-only mode first. The browser reports what would have been blocked, without blocking anything:
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; report-to csp
Reporting-Endpoints: csp="https://example.com/csp-reports"
Collect reports for a week or two, add the sources your site legitimately uses, then switch to the enforcing Content-Security-Policy header. Avoid 'unsafe-inline' and 'unsafe-eval' in script-src: they allow exactly what the policy is meant to stop. For inline scripts you cannot remove, use nonces or hashes.
Strict-Transport-Security
HSTS (RFC 6797) tells the browser to reach your site only over HTTPS from now on, so the first request after typing example.com does not go out in cleartext where it can be intercepted:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Send it on HTTPS responses; browsers ignore it over plain HTTP. Start with a short max-age and add includeSubDomains only when every subdomain serves HTTPS, because browsers remember the header. The TLS certificate checklist covers HSTS preloading and the rest of the HTTPS setup.
X-Content-Type-Options
X-Content-Type-Options: nosniff
This stops the browser from guessing a file's type from its content and, for example, running an uploaded text file as a script. It has one sensible value. Set it on every response, and make sure your server sends correct Content-Type headers, since nosniff makes the browser trust them.
frame-ancestors and X-Frame-Options
Clickjacking loads your page invisibly inside another site's frame and tricks the user into clicking it. Decide which sites, if any, may frame your pages.
The modern control is the CSP directive frame-ancestors. The older X-Frame-Options header (RFC 7034) does the same for older browsers. Browsers that support both use frame-ancestors. Setting both is harmless:
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
Use frame-ancestors 'none' and X-Frame-Options: DENY if your pages should never be framed at all.
Referrer-Policy
When a user follows a link, the browser can tell the destination which page they came from. Full URLs can carry search terms, reset tokens or internal paths. Referrer Policy limits what is sent:
Referrer-Policy: strict-origin-when-cross-origin
This sends the full URL within your own site and only the origin, such as https://example.com, to other sites, and nothing when moving from HTTPS to HTTP. Current browsers use this value by default when the header is absent, but setting it makes the choice explicit. Use no-referrer on pages with sensitive URLs.
Permissions-Policy
Permissions Policy turns off browser features your site does not use, so a compromised third-party script cannot use them either:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
List only the features you want to deny, and leave enabled what the site genuinely needs.
X-XSS-Protection
This header controlled a cross-site scripting filter in older browsers. Current browsers have removed that filter, and the filter itself could be abused to leak information from pages. Current guidance, including the OWASP HTTP Headers Cheat Sheet, is to switch it off explicitly and rely on CSP:
X-XSS-Protection: 0
Cookie flags
Cookies carry sessions, so their attributes matter as much as any header (RFC 6265):
Set-Cookie: session=...; Path=/; Secure; HttpOnly; SameSite=Lax
Securesends the cookie only over HTTPS, so it never travels in cleartext.HttpOnlyhides the cookie from JavaScript, so an injected script cannot read the session and take it elsewhere.SameSite=Lax(orStrictfor sensitive flows) stops the cookie being sent with most requests triggered by other sites, which limits cross-site request forgery.
Set all three on session and authentication cookies. A cookie that JavaScript really needs to read should not hold anything that grants access.
What TrustSek scores today
TrustSek's TLS and web security module makes one request to https:// and one to http:// on the domain you enter, as a browser would, and reads the headers of those responses. It is one reading of the front page of that one host.
Not every header in this guide produces a finding. The scan records several of them, but only the ones below are scored today:
| Header or flag | What the scan reports | Severity |
|---|---|---|
Content-Security-Policy | Security headers missing when the enforcing header is absent. A report-only policy does not count, and the policy's content is not evaluated | Medium |
Strict-Transport-Security | HSTS header missing when the HTTPS response has none. max-age and directives are not evaluated | Medium |
X-XSS-Protection | X-XSS-Protection header missing when the header is absent. X-XSS-Protection: 0 counts as present | Medium |
Secure cookie flag | Insecure cookie configuration when a cookie set over HTTPS lacks Secure | Medium |
HttpOnly cookie flag | Cookies missing HttpOnly flag when none of the cookies set carry HttpOnly | Medium |
X-Content-Type-Options, X-Frame-Options, frame-ancestors, Referrer-Policy, Permissions-Policy, SameSite | Not scored today |
A note on X-XSS-Protection: the finding's own text in the app describes the header as an extra layer of defence for older browsers. We recommend X-XSS-Protection: 0, as above, which also clears the finding.
“No finding” is not the same as a well-configured site. The scan sees one response per scheme, does not judge whether a CSP is strict or loose, and cannot see headers on pages, subdomains or APIs it did not request. Use it as a first reading, and check the headers on the pages that handle logins and personal data yourself. The methodology explains how severity feeds the score.
A starting set
Content-Security-Policy built up from report-only mode, with frame-ancestors. Strict-Transport-Security on every HTTPS response. X-Content-Type-Options: nosniff. X-Frame-Options for older browsers. Referrer-Policy: strict-origin-when-cross-origin. Permissions-Policy denying what you do not use. X-XSS-Protection: 0. Secure; HttpOnly; SameSite=Lax on session cookies.
Check your domain's headers, TLS and the rest
See which security headers and cookie flags your front page sends today, alongside TLS, email security and the rest of the outside-in score.