Overview
Apply security headers to protect against common web vulnerabilities. CORS, CSP, HSTS, and other headers are centralized in middleware.
What it is
HTTP response headers that protect against XSS, clickjacking, MIME sniffing, and other attacks.
Why we use it
Defense in depth - headers provide protection even if application code has vulnerabilities.
When to use
All responses. Configure createSecurityMiddleware() in proxy.ts or middleware.ts.
Key Features
- CORS with origin validation and Vary header
- Content Security Policy configuration
- HTTPS enforcement with HSTS
- Clickjacking prevention with X-Frame-Options
Quick Start
Configure Security Middleware
Configure security middleware with createSecurityMiddleware().
// Security middleware factory (proxy.ts or middleware.ts)
import { createSecurityMiddleware } from '@/middleware/security';
const security = createSecurityMiddleware({
cors: {
allowedOrigins: ['https://app.example.com'],
},
headers: {
enableHSTS: process.env.NODE_ENV === 'production',
csp: 'auto', // Uses strict in production, relaxed in dev
},
});
export async function middleware(request: NextRequest) {
return security.handle(request);
}Patterns
CORS Configuration
Handle cross-origin requests securely.
// CORS is configured via createSecurityMiddleware
import { createSecurityMiddleware } from '@/middleware/security';
const security = createSecurityMiddleware({
cors: {
// Allowed origins for CORS requests
allowedOrigins: ['https://app.example.com', 'https://admin.example.com'],
// Methods allowed for CORS requests
allowedMethods: 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
// Headers allowed for CORS requests
allowedHeaders: 'Content-Type, Authorization',
// Allow credentials (cookies, auth headers)
allowCredentials: true,
// Max age for preflight cache (24 hours)
maxAge: 86400,
},
});
// CORS headers are automatically applied to /api/* routes
// Preflight OPTIONS requests return 204 with proper headers
// Includes Vary: Origin header to prevent cache poisoningContent Security Policy
Configure CSP directives.
// Content Security Policy (CSP) modes
// Configured in @/middleware/security via createSecurityMiddleware
const security = createSecurityMiddleware({
headers: {
// CSP mode: 'auto' | 'strict' | 'production' | 'development' | custom
csp: 'auto',
// Enable nonce-based CSP for stronger XSS protection
enableNonce: true,
},
});
// Production CSP directives (csp: 'production')
// default-src 'self';
// script-src 'self' 'unsafe-inline' 'unsafe-eval';
// style-src 'self' 'unsafe-inline';
// img-src 'self' data:;
// font-src 'self' data:;
// connect-src 'self';
// frame-src 'none';
// frame-ancestors 'none';
// object-src 'none';
// base-uri 'self';
// form-action 'self';
// upgrade-insecure-requestsSecurity Headers
Standard security headers applied.
// Security headers applied by createSecurityMiddleware
// Source: src/middleware/security-headers.ts
const securityHeaders = {
// Prevent clickjacking
'X-Frame-Options': 'DENY',
// Prevent MIME type sniffing
'X-Content-Type-Options': 'nosniff',
// Enforce HTTPS (only when enableHSTS: true)
'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
// Control referrer information
'Referrer-Policy': 'strict-origin-when-cross-origin',
// Disable browser features
'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
// Content Security Policy (varies by csp mode)
'Content-Security-Policy': '...',
};
// Note: X-XSS-Protection is deprecated and not included
// Modern browsers use CSP for XSS protection insteadWatch Out
Overly permissive CORS (Allow-Origin: *)
Don't
// Overly permissive CORS - allows any origin
export async function OPTIONS(request: Request) {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*', // Dangerous!
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': '*',
},
});
}Do
// Use createSecurityMiddleware for CORS
import { createSecurityMiddleware } from '@/middleware/security';
const security = createSecurityMiddleware({
cors: {
allowedOrigins: ['https://app.example.com'],
allowCredentials: true,
},
});
// Middleware handles CORS automatically:
// - Validates origin against allowedOrigins
// - Returns 403 for unauthorized origins
// - Includes Vary: Origin to prevent cache poisoning
// - Supports development mode for localhostMissing HTTPS enforcement
Don't
// Missing HTTPS enforcement
// Allows HTTP connections - vulnerable to MITM attacks
export async function GET(request: Request) {
const data = await getData();
return NextResponse.json({ ok: true, data });
// No HSTS header - browser doesn't enforce HTTPS
}Do
// HTTPS enforced with HSTS via createSecurityMiddleware
import { createSecurityMiddleware } from '@/middleware/security';
const security = createSecurityMiddleware({
headers: {
// Enable HSTS in production only
enableHSTS: process.env.NODE_ENV === 'production',
},
});
// Adds header: Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
// Browser enforces HTTPS for 2 years including all subdomains- CSP bypasses via unsafe-inline
- Missing Vary: Origin header