What Are HTTP Security Headers? A Complete Guide

· 8 min read

HTTP security headers are response headers that your web server sends to the browser to control how the browser handles your site's content. They act as instructions: do not load scripts from untrusted sources, always use HTTPS, do not embed this page in an iframe, do not let the browser guess content types. Each header closes a specific class of attack, and together they form a defense-in-depth layer that costs nothing to deploy and stops a significant portion of common web attacks.

This guide explains each major security header, what attacks it prevents, how to configure it correctly, and the most common misconfigurations that leave sites exposed.

TL;DR

  • Security headers are free, require no code changes, and can be deployed in minutes -- yet most web servers ship with none configured by default.
  • Content-Security-Policy (CSP) is the most powerful header, blocking XSS and unauthorized resource loading by controlling which sources can serve content.
  • HSTS, X-Content-Type-Options, and X-Frame-Options are quick wins that each take one line to configure and close entire attack classes.
  • Start with report-only mode for CSP to catch violations without breaking your site, then switch to enforcement once you have eliminated false positives.

Why HTTP Security Headers Matter

Security headers are unusual in the web security landscape because they are entirely free, require no code changes, and can be deployed in minutes via web server configuration. They do not replace input validation, authentication, or secure coding practices -- but they add a browser-enforced layer that catches attacks your application code might miss.

The problem is that most web servers do not set these headers by default. Out of the box, Nginx, Apache, and most application frameworks return responses without any security headers at all. This means every new deployment starts in the least secure configuration, and adding headers requires explicit action.

Web Server Nginx / Apache / CDN Response Headers Content-Security-Policy Strict-Transport-Security X-Frame-Options + more... Browser Reads headers, enforces policies XSS Blocked by CSP Clickjacking Blocked by X-Frame-Options Downgrade Blocked by HSTS

Content-Security-Policy (CSP)

CSP is the most powerful and most complex security header. It tells the browser exactly which sources of content are allowed to load on your page: scripts, styles, images, fonts, frames, and more. Any content from a source not listed in the policy is blocked.

What it prevents: Cross-site scripting (XSS), data injection, and unauthorized resource loading. If an attacker manages to inject a script tag pointing to their malicious server, CSP blocks it because that server is not in the allowlist.

Example value:

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; frame-ancestors 'none'

This policy allows scripts only from the same origin and cdn.example.com, allows inline styles (necessary for many frameworks), and blocks all framing. It also permits images from the same origin and any HTTPS source, and loads fonts from Google Fonts.

Common misconfigurations:

  • 'unsafe-inline' in script-src -- this allows inline script tags, which is exactly the vector XSS attacks use. Use nonces or hashes instead.
  • 'unsafe-eval' -- allows eval(), Function(), and similar dynamic code execution. Some frameworks require it, but it significantly weakens CSP.
  • Overly broad domains -- script-src *.cloudfront.net allows scripts from any CloudFront distribution, including ones controlled by attackers.
  • Missing default-src -- without a fallback directive, any resource type not explicitly covered has no restrictions.

Recommended approach: Start with a restrictive policy using Content-Security-Policy-Report-Only, which logs violations without blocking. Review the reports, adjust the policy, and switch to enforcement once you have eliminated false positives.

Common Mistake

Adding 'unsafe-inline' to script-src to make things work. This allows the exact inline scripts that XSS attacks inject, defeating the purpose of CSP entirely. Use nonces or hashes instead.

Strict-Transport-Security (HSTS)

HSTS tells the browser to always use HTTPS when connecting to your domain. After seeing the HSTS header once, the browser automatically upgrades all future HTTP requests to HTTPS, even if the user types http:// or clicks an HTTP link.

What it prevents: SSL stripping attacks, where an attacker intercepts the initial HTTP request and serves a non-encrypted version of your site. Protocol downgrade attacks. Accidental mixed-content exposure.

Example value:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

This sets a one-year cache period, applies to all subdomains, and declares eligibility for the HSTS preload list (a list of domains that browsers hard-code as HTTPS-only, protecting even the very first connection).

Common misconfigurations:

  • Short max-age -- values under 6 months provide limited protection. Use at least 31536000 (one year).
  • Missing includeSubDomains -- without this, subdomains can still be accessed over HTTP.
  • Sending HSTS over HTTP -- the header is ignored over non-HTTPS connections. The server must redirect HTTP to HTTPS first, then set the header on the HTTPS response.

X-Content-Type-Options

This header has exactly one valid value: nosniff. It tells the browser to trust the declared Content-Type header and not try to guess (sniff) the content type based on the response body.

What it prevents: MIME sniffing attacks, where the browser interprets a non-script file (like a JSON response or an uploaded image) as executable JavaScript based on its content patterns.

Example value:

X-Content-Type-Options: nosniff

This is the simplest security header to deploy. There are no configuration options, no trade-offs, and no legitimate reason to omit it. Just set it.

X-Frame-Options

X-Frame-Options controls iframe embedding. This is the primary defense against clickjacking, where an attacker overlays your page (e.g., a "Delete Account" button) with a transparent iframe and tricks the user into clicking it.

What it prevents: Clickjacking and UI redressing attacks.

Example values:

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN

DENY blocks all framing. SAMEORIGIN allows framing only from the same origin. There is no reason to use the deprecated ALLOW-FROM value -- use CSP's frame-ancestors directive instead for selective framing control.

Note: CSP's frame-ancestors directive is the modern replacement for X-Frame-Options and provides more granular control. However, X-Frame-Options is still recommended as a fallback for older browsers that do not support CSP.

Referrer-Policy

Referrer-Policy controls how much URL information the browser includes in the Referer header when navigating from your site to another site. By default, the full URL -- including path, query parameters, and fragment -- is sent to the destination.

What it prevents: Leaking sensitive data in URLs to third parties. If your URLs contain session tokens, user IDs, search queries, or other private data, the default referrer behavior sends all of that to every external link your users click.

Example value:

Referrer-Policy: strict-origin-when-cross-origin

This sends the full URL for same-origin requests (useful for your own analytics), sends only the origin for cross-origin requests over HTTPS, and sends nothing for HTTPS-to-HTTP downgrades. This is the recommended general-purpose setting.

Stricter option: no-referrer sends no referrer information at all, but this can break analytics and some third-party integrations.

Permissions-Policy

Permissions-Policy controls which browser features your page can use: camera, microphone, geolocation, payment APIs, and more. You can disable features entirely or restrict them to specific origins.

What it prevents: Unauthorized access to device capabilities. A malicious script injected via XSS cannot activate the camera or microphone if Permissions-Policy has disabled those features for the page.

Example value:

Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self)

This disables camera, microphone, and geolocation entirely, while allowing the Payment Request API only from the same origin. If your site does not use a particular feature, disable it. The principle of least privilege applies to browser APIs just as it does to server permissions.

Best Practice

Apply the principle of least privilege to every security header. Disable all browser features you do not use via Permissions-Policy, block all framing via X-Frame-Options, and restrict content sources as tightly as possible via CSP.

Cross-Origin Headers (COOP, CORP, COEP)

Three related headers control how your resources interact with cross-origin content:

Cross-Origin-Opener-Policy (COOP)

Controls whether a new window opened from your page can access the opener via window.opener. The value same-origin isolates your page from cross-origin popups, preventing them from navigating your page or accessing its DOM.

Cross-Origin-Opener-Policy: same-origin

Cross-Origin-Resource-Policy (CORP)

Controls which origins can load your resources (images, scripts, fonts). Setting same-origin prevents other sites from hotlinking your resources. Setting cross-origin allows loading from anywhere (the default behavior).

Cross-Origin-Resource-Policy: same-origin

Cross-Origin-Embedder-Policy (COEP)

Requires all resources loaded by your page to explicitly opt in via CORS or CORP headers. When set, your page gains access to powerful APIs like SharedArrayBuffer that are otherwise restricted. Most sites do not need this unless they use Web Assembly or high-performance computing features.

Cross-Origin-Embedder-Policy: require-corp
Header Prevents Priority Content-Security-Policy XSS, data injection, resource hijacking Critical Strict-Transport-Security SSL stripping, protocol downgrade Critical X-Content-Type-Options MIME sniffing, content-type confusion High X-Frame-Options Clickjacking, UI redressing High Referrer-Policy URL data leakage to third parties Medium Permissions-Policy Unauthorized camera, mic, geo access Medium COOP / CORP / COEP Cross-origin data leaks, Spectre-style attacks Medium

Quick-Win Checklist

If you want to improve your security header posture in 30 minutes, here is the priority order. Each one is a single line in your Nginx or Apache configuration:

  1. X-Content-Type-Options: nosniff -- zero risk, no configuration decisions, just set it.
  2. X-Frame-Options: DENY -- unless your site legitimately needs to be framed, block it.
  3. Strict-Transport-Security: max-age=31536000; includeSubDomains -- if your site is already HTTPS-only, this is safe to deploy immediately. Add preload after verifying all subdomains support HTTPS.
  4. Referrer-Policy: strict-origin-when-cross-origin -- safe default that preserves same-origin analytics while protecting cross-origin referrer data.
  5. Permissions-Policy -- disable every feature you do not use (camera, microphone, geolocation, etc.).
  6. Content-Security-Policy -- start with report-only mode, review violations, then enforce. This is the most impactful header but requires the most tuning.

Key Takeaways

  1. 1 Deploy the four quick-win headers (X-Content-Type-Options, X-Frame-Options, HSTS, Referrer-Policy) immediately -- they take one line each and close entire attack classes.
  2. 2 Roll out Content-Security-Policy in report-only mode first, then tighten it iteratively until you can enforce it without breaking functionality.
  3. 3 Automate header checking in CI/CD to catch regressions -- a CDN change or server migration can silently strip security headers from your responses.

You can test your current security headers using Metric Tower's free header checker, which grades your configuration from A+ to F and shows exactly which headers are missing or misconfigured. For continuous monitoring, ' . config('app.name') . ''s security header analysis tracks headers across scans so you catch regressions when someone changes the server configuration.

For step-by-step instructions on testing and fixing your headers, read our guide on how to check HTTP security headers.

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