Skip to content
Back to skills

600 Reference E88275d7

ASecurity

Comprehensive reference for HTTP security headers, implementation patterns, attack vectors, and security hardening strategies.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
securityjavascriptpythonrustgojavarubybashreactvuenextjs

Works with

  • cli
  • api

Security analysis

A92/100
  • mediumUses curl or wget to download content
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 600-reference_e88275d7 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 600 Reference E88275d7?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 600 Reference E88275d7
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-600-reference-e88275d7/badge)](https://www.skillsdirectory.com/skills/tools-only-600-reference-e88275d7)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Security Headers Reference

Comprehensive reference for HTTP security headers, implementation patterns, attack vectors, and security hardening strategies.

## Table of Contents

1. [Core Security Headers](#core-security-headers)
2. [Content Security Policy (CSP)](#content-security-policy-csp)
3. [Cookie Security](#cookie-security)
4. [CORS Headers](#cors-headers)
5. [Referrer Policy](#referrer-policy)
6. [Permissions Policy](#permissions-policy)
7. [Attack Vectors & Mitigations](#attack-vectors--mitigations)
8. [Testing & Validation](#testing--validation)
9. [Browser Compatibility](#browser-compatibility)
10. [Implementation Patterns](#implementation-patterns)

---

## Core Security Headers

### Strict-Transport-Security (HSTS)

**Purpose**: Forces browsers to use HTTPS connections only.

**Syntax**:
```
Strict-Transport-Security: max-age=<seconds>; includeSubDomains; preload
```

**Parameters**:
- `max-age`: Duration (seconds) to remember HTTPS-only policy
- `includeSubDomains`: Apply policy to all subdomains
- `preload`: Enable HSTS preload list inclusion

**Recommended Configuration**:
```
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```

**Security Impact**:
- Prevents SSL stripping attacks
- Mitigates cookie hijacking over HTTP
- Eliminates mixed content warnings
- Risk: max-age=0 can disable HSTS

**Preload Requirements**:
1. Valid certificate
2. Redirect HTTP → HTTPS (same host)
3. HTTPS on all subdomains
4. max-age ≥ 31536000 (1 year)
5. includeSubDomains directive
6. preload directive
7. Submit to hstspreload.org

**Common Mistakes**:
```
# Too short max-age
Strict-Transport-Security: max-age=86400

# Missing includeSubDomains (subdomain vulnerability)
Strict-Transport-Security: max-age=31536000

# Preload without meeting requirements
Strict-Transport-Security: max-age=300; preload
```

### X-Frame-Options

**Purpose**: Prevents clickjacking attacks by controlling iframe embedding.

**Syntax**:
```
X-Frame-Options: DENY | SAMEORIGIN | ALLOW-FROM uri
```

**Directives**:
- `DENY`: No framing allowed
- `SAMEORIGIN`: Frame only from same origin
- `ALLOW-FROM uri`: Frame from specific URI (deprecated)

**Recommended Configuration**:
```
X-Frame-Options: DENY
```

**Security Impact**:
- Prevents UI redress attacks
- Blocks clickjacking
- Protects against drag-and-drop attacks
- Superseded by CSP frame-ancestors

**CSP Alternative** (preferred):
```
Content-Security-Policy: frame-ancestors 'none'
Content-Security-Policy: frame-ancestors 'self'
Content-Security-Policy: frame-ancestors https://trusted.com
```

**Browser Support**:
- X-Frame-Options: All modern browsers
- CSP frame-ancestors: Chrome 40+, Firefox 33+, Safari 10+

### X-Content-Type-Options

**Purpose**: Prevents MIME type sniffing.

**Syntax**:
```
X-Content-Type-Options: nosniff
```

**Security Impact**:
- Prevents browser MIME confusion attacks
- Blocks execution of JavaScript uploaded as images
- Forces browsers to respect declared Content-Type
- Mitigates polyglot file attacks

**Attack Scenario Prevented**:
```
# Without nosniff:
# Upload malicious.jpg containing JavaScript
# Browser sniffs content, detects JS, executes
# <script src="/uploads/malicious.jpg"></script>

# With nosniff:
# Browser respects Content-Type: image/jpeg
# JavaScript not executed
```

**Required For**:
- File upload systems
- User-generated content
- Dynamic script generation
- API endpoints returning JSON

### X-XSS-Protection

**Purpose**: Legacy XSS filter control (deprecated).

**Syntax**:
```
X-XSS-Protection: 0 | 1 | 1; mode=block | 1; report=<uri>
```

**Recommended Configuration**:
```
X-XSS-Protection: 0
```

**Why Disable**:
- Built-in XSS filters cause vulnerabilities
- CSP provides better protection
- Modern browsers removed XSS auditors
- Can introduce new attack vectors

**Use CSP Instead**:
```
Content-Security-Policy: script-src 'self'
```

### Referrer-Policy

**Purpose**: Controls Referer header information sent to other origins.

**Syntax**:
```
Referrer-Policy: no-referrer | no-referrer-when-downgrade | origin |
                 origin-when-cross-origin | same-origin | strict-origin |
                 strict-origin-when-cross-origin | unsafe-url
```

**Directives**:

| Policy | Same-Origin | Cross-Origin HTTPS | Cross-Origin HTTP |
|--------|-------------|-------------------|-------------------|
| `no-referrer` | None | None | None |
| `no-referrer-when-downgrade` | Full URL | Full URL | None |
| `origin` | Origin only | Origin only | Origin only |
| `origin-when-cross-origin` | Full URL | Origin only | Origin only |
| `same-origin` | Full URL | None | None |
| `strict-origin` | Origin only | Origin only | None |
| `strict-origin-when-cross-origin` | Full URL | Origin only | None |
| `unsafe-url` | Full URL | Full URL | Full URL |

**Recommended Configuration**:
```
Referrer-Policy: strict-origin-when-cross-origin
```

**Privacy Considerations**:
- `no-referrer`: Maximum privacy, breaks analytics
- `strict-origin-when-cross-origin`: Good balance
- `unsafe-url`: Leaks sensitive URLs

**Example Scenarios**:
```
# Private application
Referrer-Policy: no-referrer

# Public website with analytics
Referrer-Policy: strict-origin-when-cross-origin

# API endpoints
Referrer-Policy: no-referrer
```

---

## Content Security Policy (CSP)

### Overview

**Purpose**: Defines approved sources for content, preventing XSS and injection attacks.

**Syntax**:
```
Content-Security-Policy: <directive> <source>; <directive> <source>
```

**Deployment Modes**:
```
# Enforcement mode
Content-Security-Policy: <policy>

# Report-only mode (testing)
Content-Security-Policy-Report-Only: <policy>
```

### Fetch Directives

#### script-src

**Controls JavaScript execution sources.**

**Sources**:
```
script-src 'none'                    # Block all scripts
script-src 'self'                    # Same origin only
script-src 'self' https://cdn.com    # Self + specific domain
script-src 'unsafe-inline'           # Allow inline scripts (unsafe)
script-src 'unsafe-eval'             # Allow eval() (unsafe)
script-src 'nonce-<random>'          # Nonce-based (recommended)
script-src 'sha256-<hash>'           # Hash-based (recommended)
script-src 'strict-dynamic'          # Trust propagation
```

**Nonce Example**:
```html
<!-- Header -->
Content-Security-Policy: script-src 'nonce-2726c7f26c'

<!-- HTML -->
<script nonce="2726c7f26c">
  // Trusted script
</script>
```

**Hash Example**:
```html
<!-- Header -->
Content-Security-Policy: script-src 'sha256-xyz...'

<!-- HTML -->
<script>alert('Hello')</script>
<!-- Hash of "alert('Hello')" must match -->
```

**Strict Dynamic**:
```
script-src 'nonce-random' 'strict-dynamic'
```
- Scripts loaded by nonce/hash scripts are trusted
- Whitelist ignored (except 'unsafe-inline')
- Prevents bypasses via JSONP endpoints

#### style-src

**Controls CSS sources.**

```
style-src 'self'                     # Same origin stylesheets
style-src 'unsafe-inline'            # Inline styles (unsafe)
style-src 'nonce-<random>'           # Nonce-based
style-src 'sha256-<hash>'            # Hash-based
```

**Common Pattern**:
```
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com
```

#### img-src

**Controls image sources.**

```
img-src 'self'                       # Same origin images
img-src 'self' data:                 # Self + data URIs
img-src 'self' https:                # Self + any HTTPS
img-src *                            # Any source (permissive)
```

**Data URI Consideration**:
```
# Allow Base64 embedded images
img-src 'self' data:

# Security risk: Data URIs can bypass CSP for other types
```

#### connect-src

**Controls fetch, XHR, WebSocket, EventSource connections.**

```
connect-src 'self'                   # Same origin API calls
connect-src 'self' https://api.com   # Self + API domain
connect-src 'self' wss://ws.com      # Include WebSocket
```

**GraphQL Example**:
```
connect-src 'self' https://graphql.example.com
```

#### font-src

**Controls font sources.**

```
font-src 'self'                      # Same origin fonts
font-src 'self' https://fonts.gstatic.com
font-src 'self' data:                # Include data URIs
```

**Google Fonts Pattern**:
```
font-src 'self' https://fonts.gstatic.com
style-src 'self' https://fonts.googleapis.com
```

#### media-src

**Controls audio/video sources.**

```
media-src 'self'                     # Same origin media
media-src 'self' https://cdn.com
media-src *                          # Any source
```

#### object-src

**Controls Flash, Java, other plugins.**

```
object-src 'none'                    # Recommended (block plugins)
```

**Security Impact**:
- Prevents Flash-based attacks
- Blocks malicious plugin content
- Should always be 'none' unless legacy plugins required

#### frame-src

**Controls iframe sources.**

```
frame-src 'none'                     # No iframes allowed
frame-src 'self'                     # Same origin iframes
frame-src 'self' https://trusted.com
```

**Deprecated**: Use `child-src` or `frame-src` + `worker-src`

#### worker-src

**Controls Web Workers, Service Workers, Shared Workers.**

```
worker-src 'self'                    # Same origin workers
worker-src 'none'                    # Block workers
```

#### manifest-src

**Controls web app manifest sources.**

```
manifest-src 'self'                  # Same origin manifest
```

### Document Directives

#### base-uri

**Controls `<base>` tag URLs.**

```
base-uri 'none'                      # Block <base> tag
base-uri 'self'                      # Same origin only
```

**Security Impact**:
- Prevents relative URL hijacking
- Mitigates XSS via base tag injection

#### form-action

**Controls form submission targets.**

```
form-action 'self'                   # Same origin submissions
form-action 'self' https://pay.com   # Self + payment processor
form-action 'none'                   # Block all form submissions
```

**CSRF Protection Layer**:
```
form-action 'self'
```

#### frame-ancestors

**Controls who can frame this page (replaces X-Frame-Options).**

```
frame-ancestors 'none'               # Cannot be framed (X-Frame-Options: DENY)
frame-ancestors 'self'               # Same origin framing (X-Frame-Options: SAMEORIGIN)
frame-ancestors https://trusted.com  # Specific domain framing
```

### Navigation Directives

#### navigate-to

**Controls navigation targets (experimental).**

```
navigate-to 'self'                   # Navigate within same origin
navigate-to 'unsafe-allow-redirects' # Allow redirects
```

### Reporting Directives

#### report-uri (deprecated)

**Specifies violation report endpoint.**

```
report-uri /csp-report
```

**Deprecated**: Use `report-to` instead.

#### report-to

**Specifies Reporting API endpoint group.**

```
# Header 1: Define reporting endpoint
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"/csp-report"}]}

# Header 2: Reference in CSP
Content-Security-Policy: default-src 'self'; report-to csp-endpoint
```

### Other Directives

#### upgrade-insecure-requests

**Upgrades HTTP requests to HTTPS.**

```
Content-Security-Policy: upgrade-insecure-requests
```

**Effect**:
- HTTP → HTTPS for all subresources
- Helps migration to HTTPS
- No mixed content warnings

#### block-all-mixed-content (deprecated)

**Blocks mixed HTTP/HTTPS content.**

```
Content-Security-Policy: block-all-mixed-content
```

**Deprecated**: Use `upgrade-insecure-requests` instead.

#### require-trusted-types-for

**Enforces Trusted Types for DOM XSS prevention.**

```
Content-Security-Policy: require-trusted-types-for 'script'
```

**Effect**:
- Requires Trusted Types for dangerous DOM APIs
- Prevents DOM-based XSS
- Supported: Chrome 83+, Edge 83+

#### trusted-types

**Defines Trusted Types policy names.**

```
Content-Security-Policy: trusted-types myPolicy; require-trusted-types-for 'script'
```

**Example Usage**:
```javascript
if (window.trustedTypes && trustedTypes.createPolicy) {
  const myPolicy = trustedTypes.createPolicy('myPolicy', {
    createHTML: (string) => DOMPurify.sanitize(string)
  });

  element.innerHTML = myPolicy.createHTML(userInput);
}
```

### CSP Levels

#### CSP Level 1
- Basic fetch directives
- report-uri
- Browser support: All modern browsers

#### CSP Level 2
- Nonces and hashes
- frame-ancestors
- form-action
- plugin-types
- Browser support: Chrome 40+, Firefox 31+, Safari 10+

#### CSP Level 3
- 'strict-dynamic'
- Worker directives
- report-to
- Trusted Types
- Browser support: Chrome 52+, Firefox 52+

### CSP Best Practices

#### Progressive Enhancement

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

**Phase 2: Enforce + Monitor**
```
Content-Security-Policy: default-src 'self'; report-uri /csp-report
```

**Phase 3: Strict Policy**
```
Content-Security-Policy:
  default-src 'none';
  script-src 'nonce-random' 'strict-dynamic';
  style-src 'self';
  img-src 'self' https:;
  font-src 'self';
  connect-src 'self';
  base-uri 'none';
  form-action 'self';
  frame-ancestors 'none'
```

#### Nonce Generation

**Requirements**:
- Cryptographically random
- Unique per request
- Minimum 128 bits
- Base64 encoded

**Example (Python)**:
```python
import secrets
import base64

def generate_nonce():
    return base64.b64encode(secrets.token_bytes(16)).decode('utf-8')
```

#### Hash Generation

**Example (JavaScript)**:
```javascript
const crypto = require('crypto');

function generateScriptHash(scriptContent) {
  return crypto
    .createHash('sha256')
    .update(scriptContent)
    .digest('base64');
}

// Usage
const script = "alert('Hello')";
const hash = generateScriptHash(script);
// Content-Security-Policy: script-src 'sha256-${hash}'
```

### Common CSP Patterns

#### Static Website
```
Content-Security-Policy:
  default-src 'none';
  script-src 'self';
  style-src 'self';
  img-src 'self';
  font-src 'self';
  connect-src 'self';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none'
```

#### React/Vue SPA
```
Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  font-src 'self' data:;
  connect-src 'self' https://api.example.com;
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none'
```

#### Next.js/Nuxt SSR
```
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{NONCE}';
  style-src 'self' 'nonce-{NONCE}';
  img-src 'self' data: https:;
  font-src 'self';
  connect-src 'self';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none'
```

#### API Server
```
Content-Security-Policy:
  default-src 'none';
  frame-ancestors 'none'
```

---

## Cookie Security

### SameSite Attribute

**Purpose**: Controls cookie sending in cross-site requests.

**Syntax**:
```
Set-Cookie: name=value; SameSite=Strict|Lax|None
```

#### SameSite=Strict

**Behavior**: Cookie never sent in cross-site requests.

```
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
```

**Use Cases**:
- Session tokens
- Authentication cookies
- CSRF-sensitive operations

**User Impact**:
- Clicking external link → No cookie sent
- User must re-authenticate after external navigation

**Example Scenario**:
```
1. User logged into bank.com
2. Clicks link from email to bank.com/account
3. Cookie NOT sent (SameSite=Strict)
4. User sees login page
```

#### SameSite=Lax

**Behavior**: Cookie sent in top-level navigation GET requests.

```
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly
```

**Sent In**:
- `<a href="...">` clicks
- `window.location = "..."`
- `<link rel="prerender" href="...">`

**Not Sent In**:
- `<iframe src="...">`
- `<img src="...">`
- `fetch()`, `XMLHttpRequest`
- Form POST requests

**Use Cases**:
- Session cookies (better UX than Strict)
- Most authentication scenarios

**Example Scenario**:
```
1. User logged into bank.com
2. Clicks link from email to bank.com/account
3. Cookie SENT (top-level GET navigation)
4. User sees account page
```

#### SameSite=None

**Behavior**: Cookie sent in all cross-site requests.

```
Set-Cookie: tracking=xyz; SameSite=None; Secure
```

**Requirements**:
- MUST include `Secure` attribute
- HTTPS only

**Use Cases**:
- Third-party embeds (OAuth, payments)
- Cross-domain widgets
- Analytics/tracking

**Security Risk**:
- Vulnerable to CSRF
- Requires additional CSRF protection

#### Default Behavior

**Chrome 80+, Edge 86+, Firefox 69+**:
- No SameSite → Treated as `SameSite=Lax`
- 2-minute grace period for new cookies

### Cookie Security Attributes

#### Secure

**Purpose**: Cookie only sent over HTTPS.

```
Set-Cookie: session=abc; Secure
```

**Required For**:
- All production cookies
- SameSite=None cookies

#### HttpOnly

**Purpose**: Cookie inaccessible to JavaScript.

```
Set-Cookie: session=abc; HttpOnly
```

**Protection**:
- Prevents XSS cookie theft
- JavaScript `document.cookie` cannot access

**Use Cases**:
- Session tokens
- Authentication cookies
- Any security-sensitive cookie

#### Domain

**Purpose**: Specifies cookie scope across subdomains.

```
Set-Cookie: data=value; Domain=example.com
```

**Behavior**:
- `Domain=example.com` → Cookie sent to example.com and all subdomains
- No Domain attribute → Cookie only for exact domain

**Security Consideration**:
```
# Risky - sent to all subdomains
Set-Cookie: session=abc; Domain=example.com

# Safer - specific subdomain only
Set-Cookie: session=abc; Domain=app.example.com
```

#### Path

**Purpose**: Limits cookie to specific path.

```
Set-Cookie: data=value; Path=/app
```

**Behavior**:
- Cookie sent for `/app` and descendants
- Not sent for `/admin`

**Security Limitation**:
- Weak security boundary
- Can be bypassed with iframes/CORS

#### Max-Age / Expires

**Purpose**: Cookie expiration.

```
Set-Cookie: session=abc; Max-Age=3600
Set-Cookie: session=abc; Expires=Wed, 21 Oct 2025 07:28:00 GMT
```

**Best Practice**:
```
# Session cookie (no Max-Age/Expires)
Set-Cookie: session=abc; Secure; HttpOnly; SameSite=Strict

# Persistent cookie (short-lived)
Set-Cookie: remember=xyz; Max-Age=604800; Secure; HttpOnly; SameSite=Lax
```

### Cookie Prefixes

#### __Secure- Prefix

**Requirement**: Cookie must have `Secure` attribute and be set from HTTPS.

```
Set-Cookie: __Secure-SessionID=abc; Secure; Path=/
```

**Enforcement**:
- Browser rejects if not Secure
- Browser rejects if set from HTTP

#### __Host- Prefix

**Requirements**:
- Must have `Secure` attribute
- Must be set from HTTPS
- Must NOT have `Domain` attribute
- Must have `Path=/`

```
Set-Cookie: __Host-SessionID=abc; Secure; Path=/; HttpOnly; SameSite=Strict
```

**Security Benefit**:
- Prevents subdomain cookie injection
- Ensures cookie scope is tightly controlled

**Recommended Pattern**:
```
Set-Cookie: __Host-session=xyz; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600
```

---

## CORS Headers

### Access-Control-Allow-Origin

**Purpose**: Specifies allowed origins for cross-origin requests.

**Syntax**:
```
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Origin: null
```

**Security**:
```
# Public API - any origin
Access-Control-Allow-Origin: *

# Private API - specific origin
Access-Control-Allow-Origin: https://trusted.com

# Never use with credentials
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
# ❌ Invalid - must specify origin when using credentials
```

**Dynamic Origin**:
```python
# Whitelist approach
ALLOWED_ORIGINS = ['https://app1.com', 'https://app2.com']

origin = request.headers.get('Origin')
if origin in ALLOWED_ORIGINS:
    response.headers['Access-Control-Allow-Origin'] = origin
    response.headers['Vary'] = 'Origin'
```

### Access-Control-Allow-Credentials

**Purpose**: Allows cookies/auth in cross-origin requests.

```
Access-Control-Allow-Credentials: true
```

**Requirements**:
- Must specify explicit origin (not *)
- Requires credentials in fetch request

**Fetch Example**:
```javascript
fetch('https://api.example.com/data', {
  credentials: 'include'  // Send cookies
})
```

### Access-Control-Allow-Methods

**Purpose**: Specifies allowed HTTP methods.

```
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
```

**Preflight Response**:
```
OPTIONS /api/resource HTTP/1.1

HTTP/1.1 204 No Content
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
```

### Access-Control-Allow-Headers

**Purpose**: Specifies allowed request headers.

```
Access-Control-Allow-Headers: Content-Type, Authorization, X-Custom-Header
```

**Common Pattern**:
```
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
```

### Access-Control-Expose-Headers

**Purpose**: Specifies headers accessible to JavaScript.

```
Access-Control-Expose-Headers: X-RateLimit-Remaining, X-RateLimit-Reset
```

**Default Exposed** (no header needed):
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma

### Access-Control-Max-Age

**Purpose**: Caches preflight request results.

```
Access-Control-Max-Age: 86400
```

**Value**: Seconds to cache (max browser-dependent)

**Performance Benefit**:
- Reduces preflight requests
- Recommended: 24 hours (86400)

### CORS Preflight

**Triggered By**:
- Methods: PUT, DELETE, PATCH, custom
- Headers: Non-simple headers
- Content-Type: application/json

**Example Flow**:
```
# Preflight Request
OPTIONS /api/resource HTTP/1.1
Origin: https://app.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

# Preflight Response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400

# Actual Request
POST /api/resource HTTP/1.1
Origin: https://app.com
Content-Type: application/json

# Actual Response
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.com
```

---

## Permissions Policy

**Purpose**: Controls browser features and APIs (successor to Feature-Policy).

**Syntax**:
```
Permissions-Policy: <feature>=(<allowlist>)
```

### Common Features

#### Geolocation
```
Permissions-Policy: geolocation=(self)
Permissions-Policy: geolocation=(self "https://maps.com")
Permissions-Policy: geolocation=()
```

#### Camera
```
Permissions-Policy: camera=(self)
Permissions-Policy: camera=()
```

#### Microphone
```
Permissions-Policy: microphone=(self)
Permissions-Policy: microphone=()
```

#### Payment
```
Permissions-Policy: payment=(self "https://stripe.com")
```

#### USB
```
Permissions-Policy: usb=()
```

#### Fullscreen
```
Permissions-Policy: fullscreen=(self)
```

#### Autoplay
```
Permissions-Policy: autoplay=(self)
```

### Multiple Features
```
Permissions-Policy:
  geolocation=(self),
  camera=(),
  microphone=(),
  payment=(self "https://stripe.com"),
  usb=()
```

### Allowlist Syntax

| Syntax | Meaning |
|--------|---------|
| `*` | All origins |
| `self` | Same origin |
| `src` | iframe src origin (iframe allow attribute) |
| `none` or `()` | No origins |
| `"https://example.com"` | Specific origin |

### Iframe Allow Attribute

**HTML**:
```html
<!-- Old Feature-Policy -->
<iframe allow="geolocation https://maps.com; camera 'none'"></iframe>

<!-- New Permissions-Policy -->
<iframe allow="geolocation https://maps.com; camera 'none'"></iframe>
```

### Complete Feature List

**Available Features**:
- accelerometer
- ambient-light-sensor
- autoplay
- battery
- camera
- display-capture
- document-domain
- encrypted-media
- fullscreen
- geolocation
- gyroscope
- magnetometer
- microphone
- midi
- payment
- picture-in-picture
- publickey-credentials-get
- screen-wake-lock
- sync-xhr
- usb
- web-share
- xr-spatial-tracking

### Recommended Restrictive Policy
```
Permissions-Policy:
  accelerometer=(),
  camera=(),
  geolocation=(),
  gyroscope=(),
  magnetometer=(),
  microphone=(),
  payment=(),
  usb=()
```

---

## Attack Vectors & Mitigations

### Cross-Site Scripting (XSS)

**Attack Types**:

#### Reflected XSS
```
# Vulnerable URL
https://site.com/search?q=<script>alert(1)</script>

# Vulnerable Code
echo "Results for: " . $_GET['q'];
```

**Mitigations**:
1. Output encoding
2. CSP with script-src 'self'
3. X-Content-Type-Options: nosniff
4. Trusted Types

#### Stored XSS
```
# Attacker stores malicious script in database
INSERT INTO comments VALUES ('<script>steal_cookies()</script>');

# Victim loads page
SELECT comment FROM comments;
echo $comment;  // Executes script
```

**Mitigations**:
1. Input validation
2. Output encoding
3. CSP
4. HttpOnly cookies

#### DOM-based XSS
```javascript
// Vulnerable code
const name = location.hash.slice(1);
document.getElementById('welcome').innerHTML = 'Hello ' + name;

// Attack: https://site.com#<img src=x onerror=alert(1)>
```

**Mitigations**:
1. Use textContent instead of innerHTML
2. CSP with trusted-types
3. DOMPurify library
4. Avoid eval(), setTimeout(string)

### Clickjacking

**Attack Scenario**:
```html
<!-- Attacker's page -->
<iframe src="https://bank.com/transfer" style="opacity: 0.01; position: absolute;"></iframe>
<button style="position: absolute; top: 100px; left: 100px;">Win iPhone!</button>
```

**Mitigations**:
1. X-Frame-Options: DENY
2. CSP frame-ancestors 'none'
3. JavaScript frame-busting (unreliable)

### Man-in-the-Middle (MITM)

**Attack**:
- Intercept HTTP traffic
- Steal session cookies
- Inject malicious content

**Mitigations**:
1. HSTS
2. Secure cookie attribute
3. Certificate pinning
4. upgrade-insecure-requests

### CSRF (Cross-Site Request Forgery)

**Attack**:
```html
<!-- Attacker's site -->
<img src="https://bank.com/transfer?to=attacker&amount=1000">
```

**Mitigations**:
1. SameSite=Strict/Lax cookies
2. CSRF tokens
3. Custom request headers
4. CSP form-action
5. Verify Origin/Referer headers

### Cookie Tossing

**Attack**:
```
# Attacker controls subdomain evil.example.com
Set-Cookie: session=malicious; Domain=example.com

# Victim at example.com receives attacker's cookie
```

**Mitigations**:
1. __Host- cookie prefix
2. Avoid Domain attribute
3. Cookie integrity checks

### MIME Sniffing Attacks

**Attack**:
```
# Upload polyglot file (valid image + JavaScript)
POST /upload
Content-Type: multipart/form-data

[polyglot.jpg containing JS]

# Later
<script src="/uploads/polyglot.jpg"></script>
# Without nosniff: Browser executes JS
```

**Mitigations**:
1. X-Content-Type-Options: nosniff
2. CSP script-src restrictions
3. File type validation
4. Separate upload domain

---

## Testing & Validation

### Manual Testing Tools

#### cURL
```bash
# Check security headers
curl -I https://example.com

# Specific header
curl -I https://example.com | grep -i strict-transport

# Test HSTS
curl -I https://example.com | grep -i strict-transport-security
```

#### Browser DevTools
```
1. Open DevTools (F12)
2. Network tab
3. Select request
4. Headers → Response Headers
5. Verify security headers present
```

### Online Testing Services

#### Mozilla Observatory
- URL: observatory.mozilla.org
- Grades: A+ to F
- Tests: CSP, HSTS, cookies, CORS, subresource integrity

#### SecurityHeaders.com
- URL: securityheaders.com
- Grades: A to F
- Fast header scanning
- Recommendations provided

#### SSL Labs
- URL: ssllabs.com/ssltest
- HSTS validation
- Certificate analysis
- Protocol support

#### CSP Evaluator
- URL: csp-evaluator.withgoogle.com
- CSP policy analysis
- Identifies bypasses
- Suggests improvements

### Automated Testing

#### npm: security-headers-check
```bash
npm install -g security-headers
security-headers check https://example.com
```

#### Python: requests + analysis
```python
import requests

def check_security_headers(url):
    r = requests.get(url)
    headers = r.headers

    checks = {
        'HSTS': 'Strict-Transport-Security' in headers,
        'CSP': 'Content-Security-Policy' in headers,
        'X-Frame-Options': 'X-Frame-Options' in headers,
        'X-Content-Type-Options': 'X-Content-Type-Options' in headers,
    }

    return checks
```

### CSP Violation Reporting

#### Report Endpoint
```python
# Flask example
@app.route('/csp-report', methods=['POST'])
def csp_report():
    report = request.get_json()

    # Log violation
    app.logger.warning(f"CSP Violation: {report}")

    # Store for analysis
    db.store_csp_violation(
        document_uri=report.get('csp-report', {}).get('document-uri'),
        violated_directive=report.get('csp-report', {}).get('violated-directive'),
        blocked_uri=report.get('csp-report', {}).get('blocked-uri'),
    )

    return '', 204
```

#### Report Format
```json
{
  "csp-report": {
    "document-uri": "https://example.com/page",
    "violated-directive": "script-src 'self'",
    "blocked-uri": "https://evil.com/malicious.js",
    "line-number": 35,
    "column-number": 12,
    "source-file": "https://example.com/page"
  }
}
```

### CI/CD Integration

#### GitHub Actions
```yaml
name: Security Headers Check

on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Deploy preview
        run: npm run deploy:preview

      - name: Check headers
        run: |
          npm install -g security-headers
          security-headers check ${{ env.PREVIEW_URL }}
```

---

## Browser Compatibility

### HSTS

| Browser | Minimum Version | Notes |
|---------|-----------------|-------|
| Chrome | 4.0 | Full support |
| Firefox | 4.0 | Full support |
| Safari | 7.0 | Full support |
| Edge | 12.0 | Full support |
| IE | 11.0 | Partial support |

### CSP

| Level | Chrome | Firefox | Safari | Edge |
|-------|--------|---------|--------|------|
| CSP 1.0 | 25 | 23 | 7 | 12 |
| CSP 2.0 | 40 | 31 | 10 | 15 |
| CSP 3.0 | 59 | 58 | 15.4 | 79 |

**CSP 3 Features**:
- strict-dynamic: Chrome 52+, Firefox 52+
- worker-src: Chrome 59+, Firefox 58+
- Trusted Types: Chrome 83+

### SameSite Cookies

| Browser | Default=Lax | SameSite=None Requires Secure |
|---------|-------------|-------------------------------|
| Chrome | 80+ | 80+ |
| Firefox | 69+ | 69+ |
| Safari | 12.1+ | 12.1+ |
| Edge | 86+ | 86+ |

### Permissions-Policy

| Browser | Support | Notes |
|---------|---------|-------|
| Chrome | 88+ | Full support |
| Edge | 88+ | Full support |
| Firefox | Partial | Some features only |
| Safari | Partial | Limited features |

**Fallback**: Use Feature-Policy for older browsers
```
Feature-Policy: geolocation 'self'; camera 'none'
Permissions-Policy: geolocation=(self), camera=()
```

### Referrer-Policy

| Browser | Minimum Version |
|---------|-----------------|
| Chrome | 61+ |
| Firefox | 50+ |
| Safari | 11.1+ |
| Edge | 79+ |

---

## Implementation Patterns

### Nginx

```nginx
# /etc/nginx/conf.d/security-headers.conf

# 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'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;

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

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

# XSS filter (disable)
add_header X-XSS-Protection "0" always;

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

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

### Apache

```apache
# /etc/apache2/conf-available/security-headers.conf

<IfModule mod_headers.c>
    # HSTS
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # CSP
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"

    # Frame protection
    Header always set X-Frame-Options "DENY"

    # MIME sniffing protection
    Header always set X-Content-Type-Options "nosniff"

    # XSS filter (disable)
    Header always set X-XSS-Protection "0"

    # Referrer policy
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Permissions policy
    Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
</IfModule>
```

### Express.js (Node.js)

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

const app = express();

// Use helmet middleware
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      styleSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"],
      fontSrc: ["'self'"],
      connectSrc: ["'self'"],
      frameAncestors: ["'none'"],
      baseUri: ["'self'"],
      formAction: ["'self'"]
    }
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  },
  frameguard: {
    action: 'deny'
  },
  noSniff: true,
  xssFilter: false,
  referrerPolicy: {
    policy: 'strict-origin-when-cross-origin'
  }
}));

// Custom Permissions-Policy (not in helmet)
app.use((req, res, next) => {
  res.setHeader('Permissions-Policy', 'geolocation=(), camera=(), microphone=()');
  next();
});
```

### Flask (Python)

```python
from flask import Flask, make_response
from functools import wraps

app = Flask(__name__)

def add_security_headers(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        response = make_response(f(*args, **kwargs))

        # HSTS
        response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload'

        # CSP
        response.headers['Content-Security-Policy'] = (
            "default-src 'self'; "
            "script-src 'self'; "
            "style-src 'self'; "
            "img-src 'self' data: https:; "
            "font-src 'self'; "
            "connect-src 'self'; "
            "frame-ancestors 'none'; "
            "base-uri 'self'; "
            "form-action 'self'"
        )

        # Frame protection
        response.headers['X-Frame-Options'] = 'DENY'

        # MIME sniffing protection
        response.headers['X-Content-Type-Options'] = 'nosniff'

        # XSS filter (disable)
        response.headers['X-XSS-Protection'] = '0'

        # Referrer policy
        response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'

        # Permissions policy
        response.headers['Permissions-Policy'] = 'geolocation=(), camera=(), microphone=()'

        return response
    return decorated_function

@app.route('/')
@add_security_headers
def index():
    return 'Hello, World!'
```

### Django

```python
# settings.py

# HSTS
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

# Force HTTPS
SECURE_SSL_REDIRECT = True

# Session cookies
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Strict'

# CSRF cookies
CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = 'Strict'

# Content type sniffing
SECURE_CONTENT_TYPE_NOSNIFF = True

# Browser XSS protection (disable)
SECURE_BROWSER_XSS_FILTER = False

# Referrer policy
SECURE_REFERRER_POLICY = 'strict-origin-when-cross-origin'

# CSP (using django-csp)
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'",)
CSP_IMG_SRC = ("'self'", "data:", "https:")
CSP_FONT_SRC = ("'self'",)
CSP_CONNECT_SRC = ("'self'",)
CSP_FRAME_ANCESTORS = ("'none'",)
CSP_BASE_URI = ("'self'",)
CSP_FORM_ACTION = ("'self'",)

# middleware.py
class SecurityHeadersMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)

        # X-Frame-Options
        response['X-Frame-Options'] = 'DENY'

        # Permissions-Policy
        response['Permissions-Policy'] = 'geolocation=(), camera=(), microphone=()'

        return response
```

### Next.js

```javascript
// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=31536000; includeSubDomains; preload'
          },
          {
            key: 'Content-Security-Policy',
            value: [
              "default-src 'self'",
              "script-src 'self' 'unsafe-eval' 'unsafe-inline'",
              "style-src 'self' 'unsafe-inline'",
              "img-src 'self' data: https:",
              "font-src 'self'",
              "connect-src 'self'",
              "frame-ancestors 'none'",
              "base-uri 'self'",
              "form-action 'self'"
            ].join('; ')
          },
          {
            key: 'X-Frame-Options',
            value: 'DENY'
          },
          {
            key: 'X-Content-Type-Options',
            value: 'nosniff'
          },
          {
            key: 'X-XSS-Protection',
            value: '0'
          },
          {
            key: 'Referrer-Policy',
            value: 'strict-origin-when-cross-origin'
          },
          {
            key: 'Permissions-Policy',
            value: 'geolocation=(), camera=(), microphone=()'
          }
        ]
      }
    ];
  }
};
```

---

## Security Header Grading

### Mozilla Observatory Grades

**A+ Grade Requirements**:
- CSP with no unsafe-inline or unsafe-eval
- HSTS with max-age ≥ 6 months
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY or CSP frame-ancestors
- Referrer-Policy set
- Subresource Integrity on external scripts
- No insecure protocols

**Common Downgrades**:
- CSP with unsafe-inline: A → B
- HSTS max-age < 6 months: -10 points
- Missing X-Content-Type-Options: -5 points
- Missing Referrer-Policy: -5 points

### SecurityHeaders.com Grades

**A Grade Requirements**:
- Strict-Transport-Security
- Content-Security-Policy
- X-Frame-Options
- X-Content-Type-Options
- Referrer-Policy

**A+ Requirements** (all A requirements plus):
- CSP with no unsafe directives
- HSTS preload
- Permissions-Policy

---

## Advanced Topics

### Nonce Rotation

**Per-Request Nonce**:
```python
import secrets
from flask import Flask, render_template, g

app = Flask(__name__)

@app.before_request
def generate_nonce():
    g.nonce = secrets.token_urlsafe(16)

@app.after_request
def add_csp(response):
    csp = f"script-src 'nonce-{g.nonce}'; object-src 'none'"
    response.headers['Content-Security-Policy'] = csp
    return response

@app.route('/')
def index():
    return render_template('index.html', nonce=g.nonce)
```

**Template**:
```html
<script nonce="{{ nonce }}">
  // Trusted inline script
</script>
```

### CSP for Single-Page Apps

**Challenge**: Inline styles in React/Vue

**Solution 1: Build-time hashes**
```javascript
// webpack plugin to generate CSP with hashes
const CspHtmlWebpackPlugin = require('csp-html-webpack-plugin');

module.exports = {
  plugins: [
    new CspHtmlWebpackPlugin({
      'script-src': ["'self'"],
      'style-src': ["'self'"]
    })
  ]
};
```

**Solution 2: Nonce injection**
```javascript
// Next.js middleware
export function middleware(request) {
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
  const cspHeader = `script-src 'self' 'nonce-${nonce}'; style-src 'self' 'nonce-${nonce}'`;

  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-nonce', nonce);
  requestHeaders.set('Content-Security-Policy', cspHeader);

  return NextResponse.next({
    request: {
      headers: requestHeaders
    }
  });
}
```

### Subresource Integrity (SRI)

**Purpose**: Verify external script integrity.

```html
<script
  src="https://cdn.example.com/library.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux..."
  crossorigin="anonymous">
</script>
```

**Generate Hash**:
```bash
curl https://cdn.example.com/library.js | openssl dgst -sha384 -binary | openssl base64 -A
```

**CSP Integration**:
```
Content-Security-Policy:
  script-src 'self' https://cdn.example.com;
  require-sri-for script style
```

---

## References

### Specifications
- CSP Level 3: W3C Working Draft
- Referrer Policy: W3C Candidate Recommendation
- SameSite Cookies: RFC 6265bis
- Permissions Policy: W3C Working Draft

### Tools
- Mozilla Observatory: https://observatory.mozilla.org
- SecurityHeaders.com: https://securityheaders.com
- CSP Evaluator: https://csp-evaluator.withgoogle.com
- SSL Labs: https://www.ssllabs.com/ssltest

### Libraries
- Helmet (Node.js): https://helmetjs.github.io
- django-csp (Python): https://django-csp.readthedocs.io
- secure_headers (Ruby): https://github.com/github/secure_headers

---

**Document Version**: 1.0
**Last Updated**: 2025-10-27
**Lines**: 1200+

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.