Security Headers Every Website Should Send

Security2026-09-19TryQuickToolBox

You've locked down your server, patched your framework, and trained your team on secure coding. Yet your site remains vulnerable if it doesn't send the right HTTP security headers. These response headers tell browsers how to behave when handling your content, and missing or misconfigured headers leave the door open to cross-site scripting (XSS), clickjacking, protocol downgrade attacks, and data leakage.

In this guide, we'll cover the essential security headers every website should send, explain what each one does, and show you how to configure them correctly.

Why Security Headers Matter

Security headers are a first line of defense because they enforce browser-level policies that you control. They don't replace input validation or secure authentication, but they significantly reduce the attack surface. For example, a strict Content-Security-Policy can stop an injected script from executing, even if an attacker finds an XSS flaw.

Major browsers support these headers consistently, and adding them is usually a few lines of configuration. There's little reason not to use them.

The Essential Security Headers

Below are the headers that every production website should send. We'll cover what they do, recommended values, and common pitfalls.

1. Content-Security-Policy (CSP)

CSP is the most powerful header for mitigating XSS and data injection. It restricts which sources the browser can load scripts, styles, images, and other resources from. A good starting policy might look like:

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://images.example.com; object-src 'none'; base-uri 'self'; form-action 'self';

Start with default-src 'self' and gradually add exceptions as needed. Avoid 'unsafe-inline' for scripts if possible; use nonces or hashes instead. Test thoroughly because a misconfigured CSP can break your site.

2. HTTP Strict Transport Security (HSTS)

HSTS forces browsers to use HTTPS for all future requests to your domain. It prevents protocol downgrade attacks and cookie hijacking. A typical header:

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

The max-age is in seconds (one year). includeSubDomains applies the policy to all subdomains. preload allows your domain to be added to browser preload lists, but only use it if you're absolutely sure all subdomains support HTTPS.

3. X-Frame-Options

This header prevents your site from being embedded in an iframe, which stops clickjacking attacks. Use:

X-Frame-Options: DENY

Or SAMEORIGIN if you need to frame your own content. Modern browsers also support the frame-ancestors directive in CSP, which is more flexible. If you use CSP, you can omit X-Frame-Options, but including both provides better compatibility.

4. X-Content-Type-Options

This header stops browsers from MIME-sniffing a response away from the declared Content-Type. It's simple and effective:

X-Content-Type-Options: nosniff

Without it, a malicious file might be interpreted as executable script. Always set it.

5. Referrer-Policy

Referrer-Policy controls how much referrer information is sent with requests. A balanced default:

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

This sends the full URL for same-origin requests and only the origin for cross-origin requests. It reduces leakage of sensitive path information while preserving analytics.

6. Permissions-Policy

Formerly Feature-Policy, this header lets you enable or disable browser features like geolocation, camera, and microphone. Example:

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

Disabling unused features reduces the impact of compromised third-party scripts.

Comparison of Security Headers

HeaderPurposeRecommended Value
Content-Security-PolicyMitigate XSS and data injectiondefault-src 'self'; script-src 'self' ...
Strict-Transport-SecurityEnforce HTTPSmax-age=31536000; includeSubDomains
X-Frame-OptionsPrevent clickjackingDENY or SAMEORIGIN
X-Content-Type-OptionsStop MIME sniffingnosniff
Referrer-PolicyControl referrer leakagestrict-origin-when-cross-origin
Permissions-PolicyRestrict browser featuresgeolocation=(), camera=()

How to Add Security Headers

The method depends on your web server or framework. Here are common approaches.

Nginx

Add headers in your server block:

add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://images.example.com; object-src 'none'; base-uri 'self'; form-action 'self';" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;

The always parameter ensures headers are sent even on error responses.

Apache

Enable mod_headers and add:

Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://images.example.com; object-src 'none'; base-uri 'self'; form-action 'self';"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"

Node.js (Express)

Use the helmet middleware, which sets many headers by default:

const helmet = require('helmet');
app.use(helmet());
// Customize CSP if needed
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "https://trusted.cdn.com"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    imgSrc: ["'self'", "data:", "https://images.example.com"],
    objectSrc: ["'none'"],
    baseUri: ["'self'"],
    formAction: ["'self'"],
  }
}));

Helmet also sets other headers like X-Content-Type-Options and Referrer-Policy by default.

Testing Your Headers

After deployment, verify your headers using browser developer tools (Network tab) or online scanners like SecurityHeaders.com. Check that:

Regularly review and update your policies as your site evolves.

FAQ

What is the most important security header?

Content-Security-Policy is often considered the most important because it directly mitigates XSS and data injection attacks, which are among the most common web vulnerabilities.

Can security headers replace other security measures?

No. Security headers are a defense-in-depth layer. You still need secure coding, input validation, authentication, and other best practices.

Will adding security headers break my website?

If misconfigured, especially CSP, they can block legitimate resources. Always test in a staging environment and monitor browser console for violations before deploying to production.

Ready to lock down your site? Start by adding the headers above, then test with your browser's developer tools. For a quick way to inspect and format JSON responses from your security scanner, try our JSON Formatter.