HTTP Security Headers: Protect Your Site in 2025

THEJORD Team5 min read
development

Complete guide to HTTP security headers. CSP, HSTS, X-Frame-Options to protect your website.

HTTP Security Headers: Protect Your Site in 2025

Introduction to HTTP Security Headers

HTTP security headers are your first line of defense against common web attacks. They instruct browsers to enforce security policies that protect users from cross-site scripting (XSS), clickjacking, data injection, and other threats. This guide covers essential security headers every web application should implement.

Content Security Policy (CSP)

CSP is arguably the most powerful security header, preventing XSS and data injection attacks by controlling which resources the browser can load.

Basic CSP

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'

CSP Directives

# Control script sources
script-src 'self' https://cdn.example.com

# Control style sources
style-src 'self' 'unsafe-inline'

# Control image sources
img-src 'self' data: https:

# Control font sources
font-src 'self' https://fonts.gstatic.com

# Control frame sources
frame-src 'none'
frame-ancestors 'none'

# Control connections (fetch, WebSocket, etc.)
connect-src 'self' https://api.example.com

# Control form submissions
form-action 'self'

# Fallback for unspecified resources
default-src 'self'

CSP Special Values

  • 'self' - Same origin only
  • 'none' - Block all sources
  • 'unsafe-inline' - Allow inline scripts/styles (avoid if possible)
  • 'unsafe-eval' - Allow eval() (avoid)
  • 'nonce-abc123' - Allow specific scripts with matching nonce
  • 'sha256-...' - Allow specific inline script by hash

Recommended Production CSP

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{random}';
  style-src 'self' 'nonce-{random}';
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
  upgrade-insecure-requests;

CSP Report-Only Mode

Test CSP without blocking resources:

Content-Security-Policy-Report-Only:
  default-src 'self';
  report-uri /csp-report-endpoint

Strict-Transport-Security (HSTS)

HSTS forces browsers to use HTTPS for all future requests to your domain.

# Basic HSTS (1 year)
Strict-Transport-Security: max-age=31536000

# Include subdomains
Strict-Transport-Security: max-age=31536000; includeSubDomains

# Preload list (commit to HTTPS forever)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

HSTS Best Practices

  • Start with a short max-age (1 day) and increase gradually
  • Only add includeSubDomains if ALL subdomains support HTTPS
  • Only use preload if you're certain—it's hard to undo
  • Submit to hstspreload.org for browser preload lists

X-Frame-Options

Prevents your page from being embedded in iframes (clickjacking protection).

# Block all framing
X-Frame-Options: DENY

# Allow same-origin framing only
X-Frame-Options: SAMEORIGIN

# Deprecated: Allow specific origin
X-Frame-Options: ALLOW-FROM https://example.com

Note: Use CSP's frame-ancestors instead—it's more flexible and widely supported.

X-Content-Type-Options

Prevents browsers from MIME-sniffing responses away from the declared content type.

X-Content-Type-Options: nosniff

This prevents attacks where malicious files are disguised as harmless types. Always use it.

Referrer-Policy

Controls how much referrer information is sent with requests.

# Send no referrer at all
Referrer-Policy: no-referrer

# Only send origin (not full URL)
Referrer-Policy: strict-origin

# Send origin only when downgrading (HTTPS to HTTP)
Referrer-Policy: strict-origin-when-cross-origin

# Send full URL to same origin, origin only cross-origin
Referrer-Policy: origin-when-cross-origin

Recommended Value

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

This balances privacy (not leaking full URLs cross-origin) with functionality (analytics still get origin info).

Permissions-Policy (formerly Feature-Policy)

Controls browser features like camera, microphone, and geolocation.

Permissions-Policy:
  camera=(),
  microphone=(),
  geolocation=(self),
  payment=(self "https://payment.example.com"),
  fullscreen=(self)

Common Directives

  • camera=() - Disable camera access
  • microphone=() - Disable microphone
  • geolocation=(self) - Allow only on same origin
  • payment=(self) - Control Payment Request API
  • usb=() - Disable WebUSB
  • autoplay=(self) - Control video autoplay

X-XSS-Protection

Legacy XSS filter (deprecated but still used for older browsers).

# Disable (recommended for modern browsers with CSP)
X-XSS-Protection: 0

# Enable with blocking
X-XSS-Protection: 1; mode=block

Note: Modern browsers have deprecated this header. Use CSP instead. Setting to 0 is recommended to avoid edge cases where the filter causes issues.

Cache-Control for Security

Prevent caching of sensitive data:

# Sensitive pages (login, account, etc.)
Cache-Control: no-store, no-cache, must-revalidate, private

# Static assets
Cache-Control: public, max-age=31536000, immutable

Cross-Origin Headers

Cross-Origin-Opener-Policy (COOP)

Isolates your browsing context from cross-origin documents:

# Isolate from popups and openers
Cross-Origin-Opener-Policy: same-origin

# Allow popups but isolate
Cross-Origin-Opener-Policy: same-origin-allow-popups

Cross-Origin-Embedder-Policy (COEP)

Requires cross-origin resources to explicitly grant permission:

Cross-Origin-Embedder-Policy: require-corp

Cross-Origin-Resource-Policy (CORP)

Protect your resources from being loaded cross-origin:

# Only same-origin can load
Cross-Origin-Resource-Policy: same-origin

# Same-site can load
Cross-Origin-Resource-Policy: same-site

# Anyone can load
Cross-Origin-Resource-Policy: cross-origin

Server Configuration Examples

Nginx

server {
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # CSP
    add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;

    # Prevent MIME-sniffing
    add_header X-Content-Type-Options "nosniff" always;

    # Clickjacking protection
    add_header X-Frame-Options "DENY" always;

    # Referrer policy
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Permissions policy
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=(self)" always;
}

Express.js with Helmet

import helmet from 'helmet';

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", "data:", "https:"],
      connectSrc: ["'self'", "https://api.example.com"]
    }
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true
  },
  referrerPolicy: {
    policy: 'strict-origin-when-cross-origin'
  }
}));

Next.js

// next.config.js
const securityHeaders = [
  {
    key: 'Strict-Transport-Security',
    value: 'max-age=31536000; includeSubDomains'
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  },
  {
    key: 'X-Frame-Options',
    value: 'DENY'
  },
  {
    key: 'Referrer-Policy',
    value: 'strict-origin-when-cross-origin'
  }
];

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: securityHeaders
      }
    ];
  }
};

Testing Security Headers

Online Tools

  • SecurityHeaders.com - Grades your headers A-F
  • Mozilla Observatory - Comprehensive security scan
  • CSP Evaluator - Tests your CSP policy

Command Line

# Check headers with curl
curl -I https://example.com

# Check specific header
curl -s -D - https://example.com -o /dev/null | grep -i "strict-transport"

Browser DevTools

  1. Open DevTools (F12)
  2. Go to Network tab
  3. Select main document request
  4. View Response Headers section

Security Header Checklist

HeaderPurposePriority
Strict-Transport-SecurityForce HTTPSCritical
Content-Security-PolicyPrevent XSSCritical
X-Content-Type-OptionsPrevent MIME sniffingHigh
X-Frame-OptionsPrevent clickjackingHigh
Referrer-PolicyControl referrer leakageMedium
Permissions-PolicyDisable unused APIsMedium
Cross-Origin-*-PolicyIsolationMedium

Common Mistakes

  • Using CSP 'unsafe-inline' everywhere (defeats XSS protection)
  • Setting HSTS preload without being ready
  • Forgetting headers on error pages
  • Not testing after CDN/proxy configuration
  • Breaking functionality with overly strict CSP

Tools and Resources

For debugging headers and testing your configuration:

Conclusion

Security headers provide defense in depth for your web applications. Start with the essentials (HSTS, CSP, X-Content-Type-Options), then layer on additional protections. Test thoroughly before deploying, and monitor for CSP violations in production.

Key takeaways:

  • HSTS and CSP are critical for modern web security
  • Start with report-only mode for CSP
  • Use helmet.js or similar libraries for easy implementation
  • Test headers with online scanners regularly
  • Balance security with functionality

For more developer resources, explore our free online tools. For comprehensive security guidance, see MDN Security Headers and OWASP Secure Headers Project.