Back to scan results
Check 3 of 24

HTTP Security Headers

We send a normal HTTP GET to your homepage and inspect the response headers for the modern set of browser-side security directives. Missing headers don't break your site, but they leave specific attack classes wide open.

What this check probes

  • Strict-Transport-Security (HSTS) — forces browsers to use HTTPS. Should set max-age ≥ 31536000 (one year) and include includeSubDomains.
  • X-Content-Type-Options: nosniff — stops browsers from MIME-sniffing a response and reinterpreting it (e.g., reading text/plain as JavaScript).
  • X-Frame-Options or Content-Security-Policy: frame-ancestors — blocks clickjacking by preventing your page from being framed by a hostile site.
  • Content-Security-Policy (CSP) — allow-list of script/style/image sources. The single most effective XSS mitigation when configured correctly.
  • Referrer-Policy — controls how much URL data leaks via the Referer header. Best practice: strict-origin-when-cross-origin.
  • Permissions-Policy (formerly Feature-Policy) — disables browser features (camera, mic, geolocation, payment) you don't use.
  • X-XSS-Protection — noted but no longer required (Chrome and Firefox removed support; CSP supersedes it).

Why this matters for PCI DSS

PCI DSS 4.0 Requirement 6.2.4 requires protection against "common software attacks" — explicitly naming injection, broken access control, and request forgery. Browser security headers are the cheapest and most reliable defense against the client-side half of those attacks.

HSTS in particular pairs with Requirement 4.2.1 — it stops a network attacker from stripping HTTPS and intercepting cardholder data on first request via SSL stripping (sslstrip).

How to fix it

nginx — add to your server block:

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;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data: https:; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self';" always;

Apache — in your VirtualHost (requires mod_headers):

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 Content-Security-Policy "default-src 'self'; ..."

IIS / web.config:

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" />
      <add name="X-Content-Type-Options" value="nosniff" />
      <add name="X-Frame-Options" value="SAMEORIGIN" />
      <add name="Referrer-Policy" value="strict-origin-when-cross-origin" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Roll out CSP carefully — start in Content-Security-Policy-Report-Only mode and use the report endpoint to find legitimate inline scripts before enforcing. The Google CSP Evaluator grades your policy.

Verify the full set with securityheaders.com — aim for grade A.

Fixed it? Re-run the scan to confirm.

Run scan again