---
title: "HTTP Security Headers: Complete Guide"
description: "How to secure your website with HTTP headers: HSTS, CSP, X-Frame-Options, Permissions-Policy. Configuration for Apache, Nginx, Node.js and hosting platforms."
date: 2016-11-15
updated: 2026-04-19
category: Security
tags: ["Security", "HTTP Headers", "HSTS", "CSP", "htaccess", "nginx"]
url: https://uper.pl/en/blog/http-security-headers/
---

# HTTP Security Headers: Complete Guide

Proper HTTP header configuration is the first line of defense against many website attacks. They protect users from XSS, clickjacking, man-in-the-middle, and other threats. This guide covers all key security headers with configurations for various servers.

## Why Are Security Headers Important?

- Protect against XSS, clickjacking, MIME sniffing attacks
- Enforce HTTPS connections
- Control access to browser features
- Are checked by security audits
- Affect scores in tools like [SecurityHeaders.com](https://securityheaders.com/)

## 1. Strict-Transport-Security (HSTS)

**HSTS** enforces HTTPS connections for all requests, eliminating man-in-the-middle attack possibilities.

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

### Parameters

| Parameter | Meaning |
|-----------|---------|
| `max-age` | Validity time in seconds (31536000 = 1 year) |
| `includeSubDomains` | Apply to all subdomains |
| `preload` | Allow addition to browser preload lists |

### HSTS Preload List

Adding to the [HSTS Preload List](https://hstspreload.org/) means browsers will enforce HTTPS even on first visit. Requirements:
- Valid SSL certificate
- HTTP → HTTPS redirect
- HSTS with `max-age` minimum 1 year
- `includeSubDomains` and `preload` directives

**Note:** HSTS is irreversible for the `max-age` duration. Start with a short period (e.g., 300 seconds) and gradually increase.

## 2. Content-Security-Policy (CSP)

**CSP** defines allowed sources for scripts, styles, images, and other resources. It's the most important XSS protection header.

```http
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'
```

### Main Directives

| Directive | Controls |
|-----------|----------|
| `default-src` | Default source for all types |
| `script-src` | JavaScript scripts |
| `style-src` | CSS styles |
| `img-src` | Images |
| `font-src` | Fonts |
| `connect-src` | XHR, fetch, WebSocket |
| `frame-src` | iframe sources |
| `frame-ancestors` | Who can embed page in iframe |

### Report-Only Mode

Test CSP without blocking:

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

Detailed guide: [CSP for Google Services](/en/blog/csp-google-services/)

## 3. X-Frame-Options

**X-Frame-Options** protects against clickjacking attacks by controlling whether a page can be embedded in an iframe.

```http
X-Frame-Options: SAMEORIGIN
```

### Values

| Value | Meaning |
|-------|---------|
| `DENY` | Never allow iframe embedding |
| `SAMEORIGIN` | Only from same domain |
| `ALLOW-FROM uri` | Only from specified source (deprecated) |

**Note:** CSP `frame-ancestors` is the newer alternative. Use both for backward compatibility.

## 4. X-Content-Type-Options

**X-Content-Type-Options** prevents "MIME sniffing" - browser attempts to guess file type.

```http
X-Content-Type-Options: nosniff
```

Without this header, the browser may interpret a text file as JavaScript, enabling XSS attacks.

## 5. Referrer-Policy

**Referrer-Policy** controls what source information is sent during navigation.

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

### Values

| Value | Meaning |
|-------|---------|
| `no-referrer` | Never send referrer |
| `same-origin` | Only for same domain |
| `strict-origin` | Domain only, not on HTTPS→HTTP downgrade |
| `strict-origin-when-cross-origin` | Full URL for same-origin, domain for cross-origin (recommended) |

## 6. Permissions-Policy

**Permissions-Policy** (formerly Feature-Policy) controls access to browser features like geolocation, camera, or microphone.

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

### Syntax

- `()` - blocked for all
- `(self)` - only this domain
- `*` - allowed for all

### Popular Features

| Feature | Controls |
|---------|----------|
| `geolocation` | Geolocation API |
| `microphone` | Microphone access |
| `camera` | Camera access |
| `payment` | Payment Request API |
| `fullscreen` | Fullscreen API |

## 7. Cross-Origin Isolation (COOP, COEP, CORP)

Three related headers control how your page interacts with other origins — used together, they enable **cross-origin isolation**, which protects against Spectre-style attacks and unlocks features like `SharedArrayBuffer`.

- **Cross-Origin-Opener-Policy (COOP)** — who has access to your `window`. The safe default is `same-origin-allow-popups` — protects against tabnapping without breaking OAuth, Stripe or YouTube popups.
- **Cross-Origin-Embedder-Policy (COEP)** — forces cross-origin resources to opt in. Only needed if you want `crossOriginIsolated === true`.
- **Cross-Origin-Resource-Policy (CORP)** — set on resources *you host* to control who can load them.

```http
Cross-Origin-Opener-Policy: same-origin-allow-popups
Cross-Origin-Resource-Policy: same-site
```

Setting `COOP: same-origin` (full isolation) silently breaks many third-party integrations (YouTube Share, Stripe Checkout, Google Sign-In popups). If you need SharedArrayBuffer, accept this trade-off; otherwise stay with `same-origin-allow-popups`.

For the full breakdown — including `crossOriginIsolated`, debugging tools, and ready configurations for marketing sites vs. WASM apps — see the dedicated guide: [COOP, COEP, CORP — cross-origin isolation explained](/en/blog/coop-coep-corp-cross-origin-isolation/).

## 8. X-XSS-Protection (Deprecated)

**X-XSS-Protection** activated the built-in XSS filter in older browsers. It is **deprecated** - modern browsers (Chrome 78+) removed this filter.

```http
X-XSS-Protection: 0
```

**Why 0?** The value `1; mode=block` can cause side-channel attacks. Use CSP instead.

## Complete Configuration

### Apache (.htaccess)

```apache

```

### Nginx

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

    # CSP
    add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'" always;

    # Clickjacking
    add_header X-Frame-Options "SAMEORIGIN" always;

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

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

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

    # XSS filter disabled
    add_header X-XSS-Protection "0" always;
}
```

### Node.js (Express + Helmet)

```javascript
const helmet = require('helmet');

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", "data:", "https:"],
      frameAncestors: ["'self'"]
    }
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  },
  frameguard: { action: 'sameorigin' },
  noSniff: true,
  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
  xssFilter: false
}));
```

### Netlify (netlify.toml)

```toml
[[headers]]
  for = "/*"
  [headers.values]
    Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
    X-Frame-Options = "SAMEORIGIN"
    X-Content-Type-Options = "nosniff"
    Referrer-Policy = "strict-origin-when-cross-origin"
    Permissions-Policy = "geolocation=(), microphone=(), camera=()"
```

### Vercel (vercel.json)

```json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Strict-Transport-Security", "value": "max-age=31536000; includeSubDomains; preload" },
        { "key": "X-Frame-Options", "value": "SAMEORIGIN" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
      ]
    }
  ]
}
```

## Testing Headers

### SecurityHeaders.com

[https://securityheaders.com/](https://securityheaders.com/) - quick scan with A-F grade.

### Observatory by Mozilla

[https://observatory.mozilla.org/](https://observatory.mozilla.org/) - comprehensive security audit.

### Chrome DevTools

1. Open DevTools (F12)
2. **Network** tab
3. Select HTML document
4. Check **Response Headers**

### curl

```bash
curl -I https://example.com
```

## Security Checklist

### Critical
- [ ] **HSTS** - enforce HTTPS
- [ ] **X-Frame-Options** - clickjacking protection
- [ ] **X-Content-Type-Options: nosniff**

### Recommended
- [ ] **CSP** - XSS protection
- [ ] **Referrer-Policy** - source information control
- [ ] **Permissions-Policy** - browser API restrictions

### Deprecated (disable)
- [ ] **X-XSS-Protection: 0** - disable legacy filter

## Audit your security headers with UPER SEO Auditor

For a quick, visual check of every header covered in this guide, install our Chrome extension **[UPER SEO Auditor](https://chromewebstore.google.com/detail/uper-seo-auditor/khhpbeckpphaoiemjdijhbfpjnendage)**. The Security tab gives you:

- **HTTPS connection status** with instant red/green indicator.
- **10 security headers checked** with weighted scoring: HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, COOP, COEP, CORP, X-XSS-Protection.
- **Overall 0-10 score** weighted by header importance — HSTS and CSP count double.
- **CSP directive parser** — every directive and source listed separately, so missing domains jump out.
- **Live CSP violation capture** with a `[Google]` flag for blocks affecting Google services (GTM, GA4, Maps, Fonts).
- **security.txt detection** with parsed Contact and Expires fields.

It runs entirely in your browser, no data leaves the page, and it works on any site — yours, a client's, or a competitor's.

## Summary

Security header configuration is a simple step that significantly increases site protection:

1. **HSTS** enforces HTTPS and protects against downgrade attacks
2. **CSP** is the most powerful XSS protection
3. **X-Frame-Options** blocks clickjacking
4. **Test regularly** on SecurityHeaders.com and Observatory

Well-configured headers can prevent many attacks with minimal effort.

## Sources

1. **MDN - HTTP Security Headers**
[https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#security](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#security)

2. **OWASP - Security Headers**
[https://owasp.org/www-project-secure-headers/](https://owasp.org/www-project-secure-headers/)

3. **SecurityHeaders.com**
[https://securityheaders.com/](https://securityheaders.com/)

4. **Mozilla Observatory**
[https://observatory.mozilla.org/](https://observatory.mozilla.org/)

5. **HSTS Preload List**
[https://hstspreload.org/](https://hstspreload.org/)
