Security Header Best Practices

Security Header Best Practices

1. Progressive Enhancement Strategy

class ProgressiveSecurityHeaders {
    constructor() {
        this.stages = {
            discovery: {
                duration: '2 weeks',
                headers: {
                    'Content-Security-Policy-Report-Only': "default-src * 'unsafe-inline' 'unsafe-eval'; report-uri /csp-reports",
                    'X-Content-Type-Options': 'nosniff',
                    'X-Frame-Options': 'SAMEORIGIN'
                }
            },
            hardening: {
                duration: '2 weeks',
                headers: {
                    'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; report-uri /csp-reports",
                    'X-Content-Type-Options': 'nosniff',
                    'X-Frame-Options': 'SAMEORIGIN',
                    'Referrer-Policy': 'strict-origin-when-cross-origin'
                }
            },
            strict: {
                duration: 'permanent',
                headers: {
                    'Content-Security-Policy': "default-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'",
                    'X-Content-Type-Options': 'nosniff',
                    'X-Frame-Options': 'DENY',
                    'Referrer-Policy': 'strict-origin',
                    'Permissions-Policy': 'geolocation=(), camera=(), microphone=()'
                }
            }
        };
        
        this.currentStage = process.env.SECURITY_STAGE || 'discovery';
    }
    
    middleware() {
        return (req, res, next) => {
            const headers = this.stages[this.currentStage].headers;
            
            Object.entries(headers).forEach(([name, value]) => {
                res.setHeader(name, value);
            });
            
            // Add monitoring header
            res.setHeader('X-Security-Stage', this.currentStage);
            
            next();
        };
    }
    
    advanceStage() {
        const stages = Object.keys(this.stages);
        const currentIndex = stages.indexOf(this.currentStage);
        
        if (currentIndex < stages.length - 1) {
            this.currentStage = stages[currentIndex + 1];
            console.log(`Advanced to security stage: ${this.currentStage}`);
        }
    }
}

2. Environment-Specific Configuration

class EnvironmentAwareHeaders {
    constructor() {
        this.configs = {
            development: {
                csp: "default-src * 'unsafe-inline' 'unsafe-eval'; report-uri /dev-csp-reports",
                hsts: null, // No HSTS in development
                frameOptions: 'SAMEORIGIN',
                corsOrigins: ['http://localhost:3000', 'http://localhost:3001']
            },
            staging: {
                csp: "default-src 'self' https:; script-src 'self' 'unsafe-inline' https:; report-uri /csp-reports",
                hsts: 'max-age=300', // 5 minutes for testing
                frameOptions: 'SAMEORIGIN',
                corsOrigins: ['https://staging-app.example.com']
            },
            production: {
                csp: "default-src 'self'; script-src 'self' 'nonce-{nonce}'; style-src 'self' 'nonce-{nonce}'; upgrade-insecure-requests",
                hsts: 'max-age=31536000; includeSubDomains; preload',
                frameOptions: 'DENY',
                corsOrigins: ['https://app.example.com', 'https://mobile.example.com']
            }
        };
    }
    
    getConfig() {
        const env = process.env.NODE_ENV || 'development';
        return this.configs[env] || this.configs.development;
    }
    
    middleware() {
        const config = this.getConfig();
        
        return (req, res, next) => {
            // Generate nonce for CSP
            const nonce = crypto.randomBytes(16).toString('base64');
            res.locals.nonce = nonce;
            
            // Apply CSP with nonce substitution
            if (config.csp) {
                const csp = config.csp.replace(/{nonce}/g, nonce);
                res.setHeader('Content-Security-Policy', csp);
            }
            
            // Apply HSTS only in appropriate environments
            if (config.hsts && req.secure) {
                res.setHeader('Strict-Transport-Security', config.hsts);
            }
            
            // Frame options
            if (config.frameOptions) {
                res.setHeader('X-Frame-Options', config.frameOptions);
            }
            
            // CORS handling
            const origin = req.headers.origin;
            if (origin && config.corsOrigins.includes(origin)) {
                res.setHeader('Access-Control-Allow-Origin', origin);
                res.setHeader('Access-Control-Allow-Credentials', 'true');
            }
            
            next();
        };
    }
}

3. Documentation and Team Communication

/**
 * Security Headers Documentation Generator
 * Generates markdown documentation for current security configuration
 */
class SecurityHeadersDocGenerator {
    constructor(config) {
        this.config = config;
    }
    
    generate() {
        const doc = `# Security Headers Configuration