Security headers: practical checks for your website

Deploy CSP in report-only mode, then enforce it. Set framing, nosniff, referrer and cookie protections with exact headers and rollout steps.

Overview

HTTP security headers give browsers instructions about how to handle a response and its content. They can reduce exposure to particular attack techniques, but they do not repair vulnerable application logic or replace access controls. A useful security headers check explains which response was sampled, what instruction it advertised and which application requirements still need review.

Configuration often passes through several systems: a CDN, hosting platform, reverse proxy and application framework. Each can add, remove or duplicate headers. Review the response delivered to a visitor rather than assuming a setting in one control panel reaches the public edge. Keep ownership clear so that a later application release does not overwrite a carefully tested infrastructure rule.

Content Security Policy needs application context

Content-Security-Policy, or CSP, can restrict sources of scripts and other resources and control where a page can be framed. A policy with broad wildcards or unsafe script allowances can be present without providing the intended protection. Header presence is therefore a discovery result, not a verdict that script execution is tightly controlled. Examine directives, fallback behavior and the resources the application actually needs.

Begin with an inventory of scripts, styles, frames and network connections. Deploy the starter below as Content-Security-Policy-Report-Only first. Exercise normal workflows and inspect browser-console violations; for centralized reports, configure an owned reporting endpoint with appropriate privacy controls. The example has no reporting destination. Correct missing source permissions before enforcement. For script-heavy applications, use tested nonce or hash policies instead of broad unsafe-inline allowances. Generate a fresh unpredictable nonce for each response and apply it to the intended script elements.

When enforced, the starter permits same-origin resources, blocks plugins and forbids embedding. Inline scripts and third-party services will need deliberate changes, so trial it on staging and representative production responses before enforcing. Keep the report-only header while tuning. Once expected journeys work without unexplained violations, deliver the reviewed policy as Content-Security-Policy and verify it again. default-src does not supply frame-ancestors or base-uri; retain explicit directives. Record any required third-party source and the owner who approved it.

Starter response from https://example.com/ (observe before enforcement):
Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'

After compatibility testing, enforce the reviewed policy:
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin

Legacy framing fallback for the same no-embedding choice:
X-Frame-Options: DENY

Example session cookie on example.com (dummy value):
Set-Cookie: session=example; Path=/; Secure; HttpOnly; SameSite=Lax

Framing, content types and referrers

Use Content-Security-Policy frame-ancestors 'none' when no site should embed your page, or 'self' when same-origin embedding is required. For older clients, pair that choice with X-Frame-Options: DENY or SAMEORIGIN respectively. Avoid obsolete ALLOW-FROM. Check payment, dashboard and partner integrations in staging before enforcing. If approved partners must embed the page, allow their exact origins in frame-ancestors and test the complete ancestor chain. Report-only framing directives do not block embedding.

X-Content-Type-Options: nosniff instructs browsers to avoid certain MIME-type guessing behavior. It belongs alongside correct Content-Type values. If a script is served as text/plain, nosniff may expose the deployment problem by causing the browser to refuse it. Repair the content type instead of removing a useful hardening control solely to hide the error. Review user-uploaded files separately because storage and serving behavior matter.

Set Referrer-Policy: strict-origin-when-cross-origin as the general-purpose baseline. It preserves the full referrer for same-origin requests, sends only the origin across origins and omits it on HTTPS-to-HTTP downgrades. Choose no-referrer for pages needing stricter privacy. Test analytics and integrations before changing an existing policy, and keep secrets out of URLs regardless. A recognized token such as unsafe-url can still disclose more information than intended; presence alone does not establish an appropriate privacy policy.

HSTS, cookies and mixed content

Send Strict-Transport-Security: max-age=31536000 after confirming HTTPS redirects and completing a short HSTS ramp. Start at 300 seconds, increase to a day and a week, then one year after checking behavior. Add includeSubDomains only when subordinate services support HTTPS. Preload adds a separate browser-list commitment and needs explicit planning. Replace HTTP resource URLs with HTTPS at their source, including asset settings and templates; a header does not repair a broken third-party dependency.

Set authentication cookies with Secure, HttpOnly and SameSite=Lax by default; use Strict when cross-site entry does not need the cookie. Test sign-in, external links and federated login before tightening SameSite. Cross-site embedded sessions may require SameSite=None; Secure, with separate CSRF defenses. HttpOnly prevents ordinary JavaScript access, so classify cookies that intentionally support client-side behavior separately. The dummy session value in the example is only a syntax example; generate real session identifiers securely and never copy that value into an application.

An HTTPS page can still reference HTTP resources in its markup or styles. Browsers may upgrade or block some requests, and JavaScript can introduce others after load. A static HTML inspection identifies explicit references but cannot reproduce all browser behavior. Replace unnecessary HTTP dependencies and verify the application in a browser through an authorized review. Do not equate a pattern match with demonstrated exploitation.

What to check

First identify the response being reviewed: requested hostname, final destination, response type and date. A challenge page, redirect or server error may be generated by a different layer from the application. Do not mark the intended application as missing controls based on an unrelated access-denied response. Obtain an appropriate sample or leave that application question unresolved.

Assign each proposed improvement to an owner who can test it. For CSP, list required resources and trial the policy before enforcement. For framing, confirm legitimate embedding partners. For nosniff, validate MIME types. For referrers, examine navigation and privacy requirements. For cookies, separate session tokens from harmless preferences and confirm which component creates each cookie.

Hide server version strings in Server, X-Powered-By and CMS generator metadata where your platform supports it. For nginx, server_tokens off removes the version from its default header and error pages; remove unnecessary framework headers at the application or edge. Check the delivered response and error pages after deployment. This reduces incidental disclosure and does not replace patching. Exercise sign-in, embedded integrations and failure pages after each header change, retaining the previous configuration for rollback and documenting any exception.

Common mistakes: chasing header presence

A universal header bundle can create a green checklist while breaking real workflows. A CSP frame-ancestors directive with permissive sources might satisfy a presence check without blocking unwanted embedding. Similarly, Referrer-Policy: unsafe-url is a recognized value but can disclose more URL detail than desired. Read the actual meaning and application context before treating a recognized setting as effective protection.

Do not confuse HTML meta tags with response headers. Some CSP behavior can be delivered through a meta element, but it has restrictions and is not interchangeable with all header directives. Avoid duplicate or conflicting policies added by different infrastructure layers. Multiple CSP headers can combine restrictively, so a second policy does not necessarily loosen an existing one in the way an administrator expects.

How the free Meo audit checks this

Meo checks a usable, complete HTTPS HTML root response for a positive numeric HSTS max-age, a nonempty enforced CSP header, framing restrictions, the exact nosniff token and recognized referrer-policy tokens. Report-only CSP does not count as enforced CSP. Framing recognizes DENY, SAMEORIGIN or a frame-ancestors directive. These are limited recognition rules: they do not validate a complete CSP grammar, determine whether sources are restrictive or establish that browsers enforce the intended behavior.

On a complete, successful HTTPS root response, cookie checks count missing Secure, missing HttpOnly, missing recognized SameSite and SameSite=None without Secure, discarding names and values. Unlike the header checks, cookies do not require HTML. No cookies set means not applicable for that sample. Static HTTPS HTML inspection counts explicit HTTP resource references without fetching assets or running scripts. Technology checks recognize allowlisted public labels; exact normalized version disclosure prompts attention, while no exact version remains unknown. Neither observation proves patch status or an applicable vulnerability.

Frequently asked questions

Does a missing header prove an exploitable problem?

No. Applicability depends on the response and application. A missing instruction can justify a hardening review, but exploitability needs evidence beyond header presence and may require separately authorized testing.

Does CSP report-only count as enforced protection?

No. A report-only policy can help plan deployment and observe compatibility issues, but it does not block the behavior described by that policy. Review reporting destinations and data handling before enabling collection.

Should every cookie use HttpOnly?

Sensitive session cookies commonly should, but some cookies intentionally support client-side behavior. Classify purpose and sensitivity first. The automatic check cannot infer those requirements from the response attributes alone.

Why can a recognized referrer policy still need review?

Recognition establishes that a known token was advertised. It does not judge whether that choice minimizes information disclosure or fits the application. Review the actual policy and avoid sensitive data in URLs.

Can the instant audit see dynamically loaded resources?

It does not execute JavaScript or fetch linked assets. Static references in sampled HTML can be observed, while dynamic requests, linked stylesheets and browser-specific behavior need an additional authorized application review.

Sources and review dates

Content reviewed against the instant audit’s implemented checks and the references below. This is a content review date, not a new revision date for these standards. Confirm provider-specific settings with the responsible administrator before deployment.

Read the complete scoring method and collection limits.

Related guides

Start with your domain

Get the free instant audit before deciding whether an expanded review would help.