How to Check HTTP Security Headers

· 9 min read

Knowing which HTTP security headers your site is sending -- and which it is missing -- is the first step toward hardening your web application. The good news is that checking your headers takes less than a minute with the right tools. The harder part is interpreting the results, understanding what each missing header means, and configuring your web server to fix the gaps.

This guide covers four methods for checking your security headers, how to interpret the results, and concrete configuration examples for Nginx and Apache to remediate every common finding.

TL;DR

  • Use curl -I for quick command-line checks, browser DevTools for context-aware inspection, and online tools for automated grading and remediation advice.
  • Most servers with default configs score D or F -- adding four basic headers (HSTS, CSP, X-Content-Type-Options, X-Frame-Options) jumps you to B or higher.
  • Include the always keyword in Nginx to ensure headers appear on error responses (4xx/5xx), not just 200s.
  • Automate header validation in CI/CD to catch regressions from CDN changes, server migrations, or proxy updates.

Method 1: curl from the Command Line

The fastest way to inspect HTTP headers is with curl. The -I flag sends a HEAD request and prints only the response headers:

curl -I https://example.com

This returns something like:

HTTP/2 200
content-type: text/html; charset=UTF-8
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN

Scan the output for security headers. If you do not see content-security-policy, strict-transport-security, x-content-type-options, or referrer-policy in the response, those headers are missing and your site is not benefiting from their protection.

For a more detailed view, add -v (verbose) to see both request and response headers, which helps debug redirect chains and intermediate hops:

curl -v -I https://example.com 2>&1 | grep -i "security\|policy\|transport\|frame\|content-type-options\|referrer"

Limitation: curl tells you what headers are present, but it does not evaluate whether the values are correct. A CSP header that includes 'unsafe-inline' 'unsafe-eval' is technically present but provides minimal protection. For evaluation, you need a tool that understands header semantics.

Method 2: Browser DevTools

Every modern browser includes developer tools with a Network tab that shows full request and response headers. This is useful when you want to check headers in the context of an actual page load, including headers on subrequests (scripts, stylesheets, API calls).

1 Open DevTools F12 or Cmd+Opt+I (Ctrl+Shift+I) 2 Network Tab Click "Network" in DevTools panel 3 Reload Page Ctrl+R / Cmd+R to capture requests 4 Click Document Click the first request, view Response Headers Response Headers (look for these) content-security-policy: default-src 'self' ... strict-transport-security: max-age=31536000 x-content-type-options: nosniff x-frame-options: DENY

Steps:

  1. Open DevTools with F12 (or Cmd+Option+I on Mac, Ctrl+Shift+I on Windows/Linux)
  2. Click the Network tab
  3. Reload the page (Ctrl+R / Cmd+R) to capture the requests
  4. Click the first request in the list (usually the HTML document)
  5. Scroll down to Response Headers

DevTools shows exactly what the browser received, including any headers added by CDNs or proxies. This is the most accurate view of what your users actually see.

Limitation: Like curl, DevTools shows raw headers without evaluating their quality. You need to know what good values look like.

Method 3: Online Header Checker Tools

Online tools evaluate your headers automatically and assign a grade. They check not just whether headers are present, but whether the values are correctly configured.

Metric Tower's free HTTP security header checker is available at /tools/header-checker with no account required. Enter a URL and receive an A+ to F grade with per-header pass/fail breakdown and specific remediation recommendations.

The grading system checks ten security headers. Each missing or misconfigured header deducts points from a starting score of 100. The grade mapping runs from A+ (95-100) through A, B, C, D, down to F (0-39).

The tool highlights not just missing headers but weak configurations -- for example, an HSTS header with a max-age under six months scores lower than one with a full year. The advantage of an online tool over curl is the interpretation layer: a clear pass/fail result with a recommendation for each finding.

Method 4: Automated Scanning

For ongoing monitoring, manual checks are not sustainable. Every time someone changes the web server configuration, updates the CDN settings, or deploys a new reverse proxy, security headers can disappear. Automated scanning catches these regressions.

Metric Tower's security header analysis runs as part of a full vulnerability scan, so your security headers are checked alongside XSS, SQL injection, CORS misconfigurations, and dozens of other security checks. If a deployment removes your CSP header, the next scan catches it.

For CI/CD pipelines, you can also use curl-based scripts in your deployment pipeline to validate that expected headers are present after each deployment:

# Simple CI check: fail if HSTS header is missing
HEADERS=$(curl -sI https://yourdomain.com)
if ! echo "$HEADERS" | grep -qi "strict-transport-security"; then
    echo "ERROR: HSTS header missing after deployment"
    exit 1
fi

Understanding the Grading System

A+ 95-100 A 85-94 B 70-84 C 55-69 D 40-54 F 0-39 Excellent All headers properly set Good Most headers set, minor gaps Poor Key headers missing Failing Most headers missing Most sites without explicit security headers score D or F out of the box. Adding the 4 basic headers (HSTS, CSP, X-Content-Type, X-Frame) jumps you to B or higher.

Most web servers with default configurations score D or F. This is not because they are insecure by design -- it is because security headers require explicit configuration, and the defaults ship with no security headers at all.

The jump from F to B is straightforward: add the four critical headers (HSTS, X-Content-Type-Options, X-Frame-Options, and a basic CSP). Getting from B to A+ requires tuning your CSP to avoid unsafe-inline and unsafe-eval, adding Permissions-Policy, and configuring the cross-origin headers.

Fixing Missing Headers: Nginx

Add these directives to your Nginx server block (or http block for global application):

# Nginx security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" 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'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; frame-ancestors 'none'" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;

The always keyword ensures headers are sent even on error responses (4xx, 5xx). Without it, Nginx only adds headers on 2xx and 3xx responses, leaving your error pages unprotected.

Common Mistake

In Nginx, using add_header in a location block overrides all headers from the parent server block -- it does not merge them. Either set all security headers in every location block, or set them all at the server level.

Important: If you use add_header in a location block, it overrides (does not merge with) headers from the parent server block. Either set all headers in each location block, or set them all at the server level.

Fixing Missing Headers: Apache

Add these to your Apache configuration (httpd.conf, apache2.conf, or a .htaccess file). The Header directive requires mod_headers to be enabled:

# Apache security headers (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 "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; frame-ancestors 'none'"
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Resource-Policy "same-origin"

Enable mod_headers if it is not already active:

sudo a2enmod headers
sudo systemctl restart apache2

Fixing Missing Headers: Application Level

If you cannot modify web server configuration (e.g., on a shared hosting platform), most application frameworks let you set response headers in middleware or application code:

Express.js: Use the helmet package, which sets sensible security headers with a single line of middleware:

const helmet = require('helmet');
app.use(helmet());

Django: Enable SecurityMiddleware and configure the relevant settings in settings.py:

SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'

Laravel: Use middleware to add headers to every response, or use a CSP package like spatie/laravel-csp.

Spring Boot: Spring Security sets many security headers by default when you add the dependency. The defaults are reasonable out of the box.

Testing After Configuration

After adding or changing security headers, always verify the results:

  1. Reload your web server (nginx -t && nginx -s reload or systemctl restart apache2)
  2. curl the endpoint to confirm the headers appear in the response
  3. Check with an online tool to verify the values are correct (not just present)
  4. Test your application -- a CSP that is too restrictive can break functionality. Open the browser console and look for CSP violation reports.
  5. Check error pages -- verify headers are present on 404 and 500 responses, not just 200s

CSP is the header most likely to cause breakage. If your application uses inline scripts, third-party widgets, or dynamic eval() calls, a restrictive CSP will block them. Start with Content-Security-Policy-Report-Only to log violations without blocking, review the console output, adjust the policy, and then switch to enforcement.

Best Practice

After deploying security headers, verify them on error pages too (404, 500), not just the homepage. Use curl -I https://yoursite.com/nonexistent-page to confirm headers appear on 4xx responses.

Continuous Security Header Monitoring

Headers can regress. A CDN configuration change, a server migration, or an updated reverse proxy can silently strip security headers from responses. Set up automated checks:

  • Include header validation in your CI/CD pipeline so every deployment is verified
  • Use scheduled security scans that include header analysis
  • Monitor the header checker output periodically -- bookmark it for your critical domains

Key Takeaways

  1. 1 Use multiple checking methods: curl for quick verification, browser DevTools for real-world context, and online grading tools for actionable remediation guidance.
  2. 2 Adding four critical headers gets you from F to B -- the quickest security improvement you can make without changing application code.
  3. 3 Automate header checks in your CI/CD pipeline and scheduled scans -- security headers can disappear silently after any infrastructure change.

For a deeper understanding of what each header does and why it matters, see our complete guide to HTTP security headers. If you want to evaluate tools that check headers as part of broader security scanning, our top web security scanners comparison covers the options.

Related articles

Top 8 Web Security Scanners

Evaluate the top web security scanners for finding XSS, SQL injection, misconfigurations, and other web application vulnerabilities in your infrastructure.

· 11 min read