PatternsSecurity Patterns
Security Headers
Configure HTTP security headers to protect against common web vulnerabilities.
HSTS & Security Headers
The Risk
Without security headers, your application is vulnerable to:
- Man-in-the-middle attacks (no HTTPS enforcement)
- Clickjacking (iframe embedding)
- MIME sniffing (content type confusion)
- XSS (inline scripts allowed)
Essential Security Headers
/**
* Security headers configuration
*/
interface SecurityHeaders {
'Strict-Transport-Security': string;
'X-Content-Type-Options': string;
'X-Frame-Options': string;
'X-XSS-Protection': string;
'Referrer-Policy': string;
'Permissions-Policy': string;
'Content-Security-Policy': string;
}
const SECURITY_HEADERS: SecurityHeaders = {
// Force HTTPS for 2 years
'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
// Prevent MIME sniffing
'X-Content-Type-Options': 'nosniff',
// Prevent clickjacking
'X-Frame-Options': 'DENY',
// Enable XSS filter (legacy browsers)
'X-XSS-Protection': '1; mode=block',
// Control referrer information
'Referrer-Policy': 'strict-origin-when-cross-origin',
// Restrict browser features
'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
// Content Security Policy (see CSP pattern)
'Content-Security-Policy': "default-src 'self'; script-src 'self'",
};Server Configuration Examples
Express.js (Node.js)
import express from 'express';
import helmet from 'helmet';
const app = express();
// Use Helmet for security headers
app.use(helmet({
strictTransportSecurity: {
maxAge: 63072000,
includeSubDomains: true,
preload: true,
},
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
},
},
xFrameOptions: { action: 'deny' },
}));
// Custom headers
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
});Next.js Configuration
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'Permissions-Policy',
value: 'geolocation=(), microphone=(), camera=()',
},
],
},
];
},
};Nginx Configuration
# nginx.conf
server {
listen 443 ssl http2;
server_name example.com;
# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Prevent clickjacking
add_header X-Frame-Options "DENY" always;
# Prevent MIME sniffing
add_header X-Content-Type-Options "nosniff" always;
# XSS Protection
add_header X-XSS-Protection "1; mode=block" always;
# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# CSP
add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;
}CloudFront (AWS CDN)
{
"Comment": "Security headers for CloudFront",
"SecurityHeadersPolicy": {
"StrictTransportSecurity": {
"Override": true,
"AccessControlMaxAgeSec": 63072000,
"IncludeSubdomains": true,
"Preload": true
},
"XContentTypeOptions": {
"Override": true
},
"XFrameOptions": {
"Override": true,
"FrameOption": "DENY"
},
"XSSProtection": {
"Override": true,
"Protection": true,
"ModeBlock": true
},
"ReferrerPolicy": {
"Override": true,
"ReferrerPolicy": "strict-origin-when-cross-origin"
}
}
}Header Descriptions
Strict-Transport-Security (HSTS)
Forces HTTPS connections for specified duration.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadmax-age: 2 years in secondsincludeSubDomains: Apply to all subdomainspreload: Include in browser preload list
X-Frame-Options
Prevents clickjacking by controlling iframe embedding.
X-Frame-Options: DENYOptions:
DENY: No framing allowedSAMEORIGIN: Only same originALLOW-FROM uri: Specific origin (deprecated)
X-Content-Type-Options
Prevents MIME type sniffing.
X-Content-Type-Options: nosniffReferrer-Policy
Controls how much referrer information is sent.
Referrer-Policy: strict-origin-when-cross-originPermissions-Policy
Controls browser features.
Permissions-Policy: geolocation=(), microphone=(), camera=()Validation Tool
/**
* Check if headers are properly configured
*/
async function validateSecurityHeaders(url: string): Promise<void> {
const response = await fetch(url);
const headers = response.headers;
const requiredHeaders = [
'strict-transport-security',
'x-content-type-options',
'x-frame-options',
];
const missing: string[] = [];
requiredHeaders.forEach((header) => {
if (!headers.has(header)) {
missing.push(header);
}
});
if (missing.length > 0) {
console.warn('Missing security headers:', missing);
} else {
console.log('✓ All required security headers present');
}
}OWASP Protection
Security headers protect against:
- A05:2021 – Security Misconfiguration
- A03:2021 – Injection
- Clickjacking
- MIME sniffing attacks
Best Practices
- HSTS: Always use with max-age 2+ years
- CSP: Start strict, relax as needed
- Test thoroughly: Headers can break functionality
- Use helmet.js: For Node.js apps
- Check with tools: SecurityHeaders.com
- Preload HSTS: Submit to hstspreload.org
- Monitor: Log CSP violations
Testing
# Check headers with curl
curl -I https://example.com
# Test with Security Headers scanner
https://securityheaders.com
# Test CSP with browser console
# Check for CSP violations in consoleSecurity headers are free protection with zero performance cost. Configure them immediately.