Skip to content

HTTP security headers: which to set, how to check them and how Mozilla grades them

Published 7 October 20269 min readBy the SmoothSeen editorial team

HTTP security headers are lines your server adds to every response so the browser applies protections: always use HTTPS (Strict-Transport-Security), restrict where scripts can load from (Content-Security-Policy), stop other sites from framing yours (frame-ancestors) or stop the browser guessing a file's type (X-Content-Type-Options). They will not lift your Google rankings: they protect your visitors and your reputation.

Key points

  • Security headers are instructions your server sends with every response so the browser enforces HTTPS, restricts scripts or stops other sites from framing yours.
  • Google says that, beyond Core Web Vitals, other page experience aspects don't directly help a site rank higher; headers protect your visitors, they don't lift positions.
  • Start a Content-Security-Policy in Report-Only mode, which reports what it would block without blocking anything.
  • Mozilla's HTTP Observatory starts every site at 100, deducts penalties and only adds bonuses if the score is still 90 or above; grades run from A+ to F.
  • `curl -sI` shows in a second which headers your server actually sends.

To check it on your own site: SEO audit

On this page

They belong to the security and trust part of SEO, alongside HTTPS and email authentication. This guide explains what each one does, which value to start with so nothing breaks, and how to check the result.

Do security headers help SEO?

Not directly, and it is worth being clear about it. Google says that, beyond Core Web Vitals, other page experience aspects don't directly help a website rank higher, although they make it more satisfying to use, which is what its ranking systems seek to reward1. No Google documentation names Content-Security-Policy or Referrer-Policy as a signal.

The real benefit lies elsewhere. A well-built content policy makes it harder for a flaw in a plugin to end up injecting scripts or spam links into your pages, and a hacked site does have visible consequences in Google: warnings in the results and interstitial warning pages in the browser, as covered in the guide to HTTPS and SEO. Headers are prevention, not a shortcut to the top.

The headers, one by one

Header
Strict-Transport-Security
What it protects against
Someone on the network forcing an unencrypted connection
Value to start with
max-age=31536000; includeSubDomains
Header
Content-Security-Policy
What it protects against
Injected scripts (XSS) and resources from unexpected origins
Value to start with
Report-Only mode first
Header
X-Content-Type-Options
What it protects against
The browser "guessing" a file's type
Value to start with
nosniff
Header
X-Frame-Options / frame-ancestors
What it protects against
Another site loading yours in an iframe (clickjacking)
Value to start with
SAMEORIGIN / frame-ancestors 'self'
Header
Referrer-Policy
What it protects against
Full URLs leaking to other sites
Value to start with
strict-origin-when-cross-origin
Header
Permissions-Policy
What it protects against
Unwanted use of camera, microphone or location
Value to start with
camera=(), microphone=(), geolocation=()
Header
Set-Cookie attributes
What it protects against
Theft of the session cookie
Value to start with
Secure; HttpOnly; SameSite=Lax

Strict-Transport-Security (HSTS)

HSTS is the header that tells the browser to connect to your domain only over HTTPS for max-age seconds. The browser ignores it if it arrives over HTTP, and it does not protect the first visit: it only takes effect after a secure connection in which the header was received2.

includeSubDomains extends the rule to every subdomain, so check they all have a certificate before you add it. The preload directive is for getting onto the list browsers ship with, and it requires a max-age of at least one year (31,536,000 seconds) plus includeSubDomains2. It is hard to undo: domains can be removed from the list, but the change takes months to reach users3. Add it only once everything else has been working for a while.

Content-Security-Policy (CSP)

A Content-Security-Policy is a list of the origins from which the page may load scripts, styles, images and other resources. Its main purpose is to guard against cross-site scripting (XSS)4. The most used directives:

  • default-src: the fallback for anything without its own directive.
  • script-src: where scripts may come from. MDN advises against 'unsafe-inline', because it defeats much of the protection; the alternative is nonces or hashes4.
  • object-src 'none' and base-uri 'self': close two classic injection routes.
  • upgrade-insecure-requests: tells the browser to load over HTTPS anything linked over HTTP.
  • frame-ancestors: who may embed your page. Set to 'none', it is equivalent to X-Frame-Options: DENY; it does not fall back to default-src and does not work in a <meta> tag, only as a header5.

Starting with Content-Security-Policy-Report-Only

A CSP written blind usually breaks something: analytics, a chat widget, an embedded map. That is why Content-Security-Policy-Report-Only exists. It monitors violations without enforcing them: the browser logs them in the console and, if you declare an endpoint, sends them to you6. MDN recommends declaring report-to (with the Reporting-Endpoints header) as well as the older report-uri, because the former does not yet have full cross-browser support6.

The practical method: publish the policy in Report-Only mode, browse every template, review what would have been blocked, add the legitimate origins and, once the console is clean, rename the header to Content-Security-Policy.

X-Content-Type-Options

With nosniff, the browser stops guessing a file's type and respects the Content-Type the server declares. It also blocks scripts that do not arrive with a JavaScript type and stylesheets that do not arrive as text/css7. Before you switch it on, check that your server declares types correctly.

X-Frame-Options and frame-ancestors

X-Frame-Options accepts DENY and SAMEORIGIN. The ALLOW-FROM variant is obsolete: modern browsers ignore the whole header if they see it. Setting it in a <meta> tag has no effect8. To choose precisely who may frame you, use frame-ancestors; keeping X-Frame-Options as well covers older browsers.

Referrer-Policy

If you declare nothing, browsers apply strict-origin-when-cross-origin: within your site the full URL is sent as the referrer, to other sites only the origin, and nothing when moving from HTTPS to HTTP9. Declaring it explicitly avoids relying on each browser's default. If your URLs carry personal data in their parameters, no-referrer is the safer choice.

Permissions-Policy

Permissions-Policy allows or blocks browser features, such as the camera, microphone or geolocation, for your page and for the iframes it embeds. camera=() disables it for everyone. MDN notes that it does not yet work in all major browsers10, so treat it as an extra layer, not your only defence.

Cookies: Secure, HttpOnly and SameSite

Cookies do not have a header of their own; they rely on the attributes of Set-Cookie. Secure means the cookie only travels over HTTPS; HttpOnly stops JavaScript reading it, which limits the damage of an XSS; SameSite=Strict or Lax restricts sending it on requests from other sites, and SameSite=None requires Secure11. Some browsers apply Lax if you leave it out, but not all, so declare it. The __Host- prefix forces the cookie to be Secure, with no Domain and with Path=/11.

The ones you can drop

OWASP recommends not sending X-XSS-Protection at all, or sending it as 0, because the old filter in some browsers could open holes in otherwise safe sites. It also advises removing X-Powered-By and not revealing versions in Server12.

A commented example header block

This is a generic starting point for a site that only loads its own resources. Lines beginning with # are comments: they are not part of the HTTP response and should not be copied.

# HTTPS only for one year, subdomains included (check first that they all have a certificate)
Strict-Transport-Security: max-age=31536000; includeSubDomains

# Report-only first: tells you what it would block, blocks nothing
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; upgrade-insecure-requests; report-to csp

# Where the browser sends the reports for the policy above
Reporting-Endpoints: csp="https://www.example.com/csp-reports"

# The browser respects Content-Type and does not guess
X-Content-Type-Options: nosniff

# For browsers that do not understand frame-ancestors
X-Frame-Options: SAMEORIGIN

# Other sites only receive your origin, not the full URL
Referrer-Policy: strict-origin-when-cross-origin

# Camera, microphone and location disabled for the page and its iframes
Permissions-Policy: camera=(), microphone=(), geolocation=()

# Session cookie: HTTPS only, invisible to JavaScript, bound to this host
Set-Cookie: __Host-session=value; Path=/; Secure; HttpOnly; SameSite=Lax

If you use analytics, a tag manager, external fonts or a chat widget, default-src 'self' would block them: Report-Only mode will tell you which origins to add. How you write these lines depends on your server or CDN, but the values are the same.

How do you check your headers with curl?

The quickest way to see what your server sends, rather than what you think it sends, is to request only the headers from the terminal (replace example.com with your domain):

# Every header in the response
curl -sI https://www.example.com/

# Only the security ones (the match is case-insensitive)
curl -sI https://www.example.com/ | grep -iE "strict-transport|content-security|x-content-type|x-frame|referrer-policy|permissions-policy|set-cookie"

# Does the http version redirect to https in a single hop?
curl -sI http://example.com/ | grep -iE "^(HTTP|location)"

Repeat the second command with one URL per template and with a static file (an image or a .js file): it is common for the home page to carry the headers while resources served by another layer, such as a CDN, do not. If the third command shows more than one hop, review your redirect chains as explained in the guide to technical SEO.

How does Mozilla's HTTP Observatory grade a site?

The HTTP Observatory is MDN's free tool that analyses a site's headers and gives it a grade. Every site starts at 100 points; penalties are deducted first and, only if the result is still 90 or above, bonuses are added. The minimum score is 0 and the highest possible is currently 14513:

Score
100 or more
Grade
A+
Score
90-99
Grade
A
Score
85-89
Grade
A-
Score
80-84
Grade
B+
Score
70-79
Grade
B
Score
65-69
Grade
B-
Score
60-64
Grade
C+
Score
50-59
Grade
C
Score
45-49
Grade
C-
Score
40-44
Grade
D+
Score
30-39
Grade
D
Score
25-29
Grade
D-
Score
0-24
Grade
F

Mozilla points out that what is unnecessary for one site may mitigate important risks for another, and that each team has to decide what suits it13. The current tests cover CSP, cookies, CORS, redirection to HTTPS, Referrer-Policy, HSTS, Subresource Integrity, X-Content-Type-Options, X-Frame-Options and the Cross-Origin policies (COEP, COOP and CORP)14. Since 2024 it no longer scores X-XSS-Protection or analyses the TLS certificate15. Permissions-Policy is not part of the grade, even though it is good practice.

What SmoothSeen checks under security and trust

Disclosure: this blog belongs to SmoothSeen. In the security and trust category of its SEO analysis, SmoothSeen shows your domain's HTTP Observatory grade, checks that the page is served over HTTPS without mixed content, looks at whether Google Web Risk flags it as dangerous and reviews the domain's SPF and DMARC records, which are explained in the guide to SPF, DKIM and DMARC. If you compare against competitors, you also see their header grade.

Frequently asked questions

Does a poor HTTP Observatory grade lower my Google rankings?

Google has made no statement to that effect. It says that, apart from Core Web Vitals, page experience aspects don't directly help a site rank. The Observatory grade measures whether you use browser defences against common attacks; improving it reduces the risk of being hacked, and a hack does have consequences in Google if it happens.

Can I set security headers in a meta tag?

Only some. A basic Content-Security-Policy can go in a <meta http-equiv> tag, but frame-ancestors does not work there, and X-Frame-Options in a meta tag has no effect at all. Report-Only mode, HSTS and cookie attributes only exist as HTTP headers. Whenever you can, configure them on the server or the CDN.

Is HSTS with preload risky?

It can be if you are not ready. Once the domain is on the browsers' preload list, every subdomain must use HTTPS, and leaving the list takes months to take effect. Before adding preload, check that every subdomain, including internal ones and those used by third-party tools, has a valid certificate.

Why does my CSP break Google Analytics or the tag manager?

Because those services load scripts from, and send data to, domains other than yours, and a policy with default-src 'self' only allows your own. Publish the policy in Report-Only mode first, check in the console which origins would be blocked and add them to script-src and connect-src before you enforce the real policy.

What to do next

Run the second curl command against your home page and one URL per template, and note which headers are missing. Start with nosniff, Referrer-Policy and HSTS, which rarely break anything, and leave the CSP in Report-Only mode for a few weeks. To see where security fits in the bigger picture, go back to the guide to what SEO is.

Sources

  1. 1Understanding page experience in Google Search results, Google Search Central, updated 22 September 2026.
  2. 2Strict-Transport-Security header, MDN, updated 11 September 2026.
  3. 3HSTS Preload List Submission, hstspreload.org, accessed 7 October 2026.
  4. 4Content-Security-Policy (CSP) header, MDN, updated 22 March 2026.
  5. 5CSP: frame-ancestors, MDN, updated 27 August 2026.
  6. 6Content-Security-Policy-Report-Only header, MDN, updated 22 March 2026.
  7. 7X-Content-Type-Options header, MDN, updated 17 March 2026.
  8. 8X-Frame-Options header, MDN, updated 17 September 2026.
  9. 9Referrer-Policy header, MDN, updated 4 September 2026.
  10. 10Permissions-Policy header, MDN, updated 14 September 2026.
  11. 11Set-Cookie header, MDN, updated 1 September 2026.
  12. 12HTTP Security Response Headers Cheat Sheet, OWASP Cheat Sheet Series, accessed 7 October 2026.
  13. 13HTTP Observatory Scoring Methodology, MDN, accessed 7 October 2026.
  14. 14mdn-http-observatory: src/analyzer/tests, MDN on GitHub, accessed 7 October 2026.
  15. 15Introducing the MDN HTTP Observatory, MDN Blog, accessed 7 October 2026.

How to cite this article

SmoothSeen. (2026, October 7). HTTP security headers: which to set, how to check them and how Mozilla grades them. https://smoothseen.com/en/blog/http-security-headers/

Who writes this

SmoothSeen is a website audit tool that measures visibility in search engines and AI assistants and delivers reports under the agency's own brand.

This blog belongs to SmoothSeen: when an article discusses the product, it does so knowing the product is ours. Third-party figures link to their original source.

Change history

  • First version.

Keep reading

HTTP security headers: which to set and how to check them