How to improve your security headers grade
CentralCSP Team ·
Last update:
A scanner gave you a low security headers grade, and now you need to know which headers to set and how. The grade is a checklist score: a tool reads your response headers and marks each recommended one present or missing, then weighs how well the ones present are configured. To raise the grade you send the right set of headers with the right values. This is that set, what each header does, and the value to ship, with the deeper fixes linked from each step.
Different scanners weight things differently. securityheaders.com checks for a fixed list of headers and downgrades you for missing ones. Mozilla Observatory (the MDN Observatory) scores the CSP more strictly and rewards a policy without 'unsafe-inline'. Rating agencies layer their own naming on the same checks. The headers below cover all of them.
The headers a scanner grades
Six headers carry almost all of the grade. Set these and configure them well, and an A is reachable.
Content Security Policy, the heaviest single factor
A Content Security Policy (CSP) tells the browser which scripts, styles, and other resources a page may load. It is the one header most scanners weight highest, and a strict CSP with no 'unsafe-inline' is what earns the top marks on a CSP-aware scanner like Mozilla Observatory.
Content-Security-Policy:
default-src 'self';
script-src 'nonce-{RANDOM}' 'strict-dynamic';
object-src 'none';
base-uri 'none';
frame-ancestors 'none'A CSP is also the header most likely to break the page if you guess at it, so deploy it in report-only first, collect what real traffic blocks, then enforce. The full method is in how to build a strong CSP, step by step, and the keyword to remove first is covered in why you should never use unsafe-inline in CSP.
Strict-Transport-Security (HSTS), enforce HTTPS
Strict-Transport-Security tells the browser to only ever reach your site over HTTPS, which closes the gap where a first request goes out in plaintext. Send a long max-age and include subdomains. Add preload only when you are ready to commit the domain to the browser preload list, since it is hard to undo.
Strict-Transport-Security: max-age=63072000; includeSubDomainsX-Content-Type-Options, stop MIME sniffing
X-Content-Type-Options: nosniff stops the browser from second-guessing a response's declared content type, which is how some uploads turn into executable scripts. It has one value and no modern replacement, so set it everywhere.
X-Content-Type-Options: nosniffFrame control, prefer frame-ancestors
Clickjacking protection decides who may embed your page in a frame. The modern control is the CSP frame-ancestors directive, which supports multiple origins and 'none'. The old X-Frame-Options header still satisfies some scanner checks and works as a fallback for very old browsers, but frame-ancestors is the one doing the work today. Why the older header is on its way out is covered in legacy security headers you can retire.
Content-Security-Policy: frame-ancestors 'none'Referrer-Policy, limit what you leak
Referrer-Policy controls how much of the current URL is sent in the Referer header when a user navigates away or a page loads a resource. A sensible default keeps the origin on cross-origin requests and the full path same-origin.
Referrer-Policy: strict-origin-when-cross-originPermissions-Policy, switch off features you do not use
Permissions-Policy controls access to browser features like the camera, microphone, and geolocation. Disabling the ones your site does not use shrinks what an injected script can reach. It is the standardized successor to the deprecated Feature-Policy, explained in Permissions-Policy explained.
Permissions-Policy: geolocation=(), camera=(), microphone=()The order to fix them in
Set the low-risk headers first, because they cannot break the page: X-Content-Type-Options, Referrer-Policy, Strict-Transport-Security, and Permissions-Policy are single-line additions you can ship today. They will move the grade immediately.
Save the CSP for last, because it is the one that needs the report-only, collect, enforce cycle to avoid breaking real traffic. It is also the heaviest factor, so it is worth the extra care.
If your low grade comes from a rating agency
Security rating agencies grade the same headers but publish their own finding names, and the fix is the same set of headers configured well. If your finding came from one of them, the per-agency walkthroughs map each finding to a header change:
Head-to-head comparisons
Several of these headers have a close cousin they get confused with. When you are deciding between two, these break down the trade-off:
- X-Frame-Options vs frame-ancestors for framing control.
- HSTS vs upgrade-insecure-requests for forcing HTTPS.
- no-cache vs no-store for keeping sensitive responses out of shared caches.
- SameSite vs CSRF tokens for cross-site request defense.
For the full reference on each header, see the security headers documentation.
See your current state first
Before you change anything, scan what the live site sends. A scan lists which headers are present, which are missing, and which carry weak values, so you fix in one informed pass instead of guessing. The security headers scanner gives you that list, the CSP scanner reports on the policy specifically, and the CSP evaluator grades a draft policy before you ship it. Once the headers are in place, the CSP suite collects the violation reports and tracks the policy over time so the grade does not quietly slip after the next deploy.
Where this leaves you
A security headers grade is a checklist, so raising it is a checklist too: send X-Content-Type-Options, Referrer-Policy, Strict-Transport-Security, and Permissions-Policy now, then build and enforce a strict CSP with frame-ancestors for the heaviest part of the score. Scan first so you know your starting point, and keep scanning so a new third-party script does not undo the work.
To collect violation reports, track your policy over time, and watch the headers across your estate, start free with CentralCSP.