Back to blog
InspectionJanuary 1, 2024· 19 min read

Server Response Header Analysis: A Developer's Guide

A practical Fusebox guide to server response header analysis.

Server Response Header Analysis: A Developer's Guide

Response headers reveal your server's secrets—from the technology stack to security misconfigurations. A 2023 security audit found that 67% of web applications leak sensitive information through headers, while 45% miss critical security headers entirely. This guide provides JavaScript tools to analyze response headers, detect vulnerabilities, and optimize server configurations.

Why Response Headers Matter

When Target's servers leaked internal hostnames through X-Backend-Server headers, attackers mapped their entire infrastructure. When Equifax forgot to remove X-Powered-By headers, hackers identified outdated frameworks. Response headers are your server's metadata—configure them wrong, and you're broadcasting vulnerabilities to the world.

Response Header Analyzer

Comprehensive header analysis tool:

// Response Header Analyzer
class ResponseHeaderAnalyzer {
    constructor() {
        this.headers = new Map();
        this.issues = [];
        this.recommendations = [];
    }
    
    // Analyze current page headers
    async analyzeCurrentPage() {
        const response = await fetch(window.location.href, { method: 'HEAD' });
        return this.analyzeResponse(response);
    }
    
    // Analyze any URL
    async analyzeURL(url) {
        try {
            const response = await fetch(url, { 
                method: 'HEAD',
                mode: 'cors',
                credentials: 'omit'
            });
            return this.analyzeResponse(response);
        } catch (error) {
            // Fallback to same-origin request
            if (error.message.includes('CORS')) {
                console.warn('CORS blocked, trying same-origin analysis');
                return this.analyzeSameOrigin(url);
            }
            throw error;
        }
    }
    
    // Analyze response object
    analyzeResponse(response) {
        // Extract headers
        this.extractHeaders(response);
        
        const analysis = {
            url: response.url,
            status: response.status,
            headers: Object.fromEntries(this.headers),
            security: this.analyzeSecurityHeaders(),
            caching: this.analyzeCachingHeaders(),
            compression: this.analyzeCompressionHeaders(),
            server: this.analyzeServerHeaders(),
            custom: this.analyzeCustomHeaders(),
            issues: this.issues,
            score: this.calculateScore(),
            recommendations: this.generateRecommendations()
        };
        
        return analysis;
    }
    
    // Extract headers from response
    extractHeaders(response) {
        this.headers.clear();
        
        // Get all headers
        for (const [key, value] of response.headers.entries()) {
            this.headers.set(key.toLowerCase(), value);
        }
        
        // Add computed headers
        this.headers.set('status', response.status.toString());
        this.headers.set('url', response.url);
        this.headers.set('type', response.type);
    }
    
    // Analyze same-origin resources
    async analyzeSameOrigin(url) {
        // Use performance API for same-origin resources
        const entries = performance.getEntriesByName(url);
        if (entries.length === 0) {
            // Trigger a fetch to get timing
            await fetch(url).catch(() => {});
        }
        
        const entry = performance.getEntriesByName(url)[0];
        if (!entry) {
            throw new Error('Could not analyze resource');
        }
        
        // Limited analysis from timing data
        return {
            url: entry.name,
            timing: {
                duration: entry.duration,
                transferSize: entry.transferSize,
                encodedBodySize: entry.encodedBodySize,
                decodedBodySize: entry.decodedBodySize,
                serverTiming: entry.serverTiming || []
            },
            analysis: 'Limited analysis due to CORS restrictions'
        };
    }
    
    // Analyze security headers
    analyzeSecurityHeaders() {
        const security = {
            score: 100,
            present: [],
            missing: [],
            misconfigured: []
        };
        
        // Required security headers
        const requiredHeaders = {
            'strict-transport-security': {
                name: 'HSTS',
                validator: (value) => {
                    const maxAge = value.match(/max-age=(\d+)/);
                    if (!maxAge || parseInt(maxAge[1]) < 31536000) {
                        return 'max-age should be at least 31536000 (1 year)';
                    }
                    if (!value.includes('includeSubDomains')) {
                        return 'Should include includeSubDomains';
                    }
                    return null;
                }
            },
            'x-content-type-options': {
                name: 'X-Content-Type-Options',
                validator: (value) => value === 'nosniff' ? null : 'Should be "nosniff"'
            },
            'x-frame-options': {
                name: 'X-Frame-Options',
                validator: (value) => {
                    if (!['DENY', 'SAMEORIGIN'].includes(value)) {
                        return 'Should be DENY or SAMEORIGIN';
                    }
                    return null;
                }
            },
            'x-xss-protection': {
                name: 'X-XSS-Protection',
                validator: (value) => {
                    // Note: This header is deprecated but still checked
                    if (value === '0') {
                        return 'XSS protection is disabled';
                    }
                    return null;
                }
            },
            'content-security-policy': {
                name: 'CSP',
                validator: (value) => {
                    if (value.includes('unsafe-inline') || value.includes('unsafe-eval')) {
                        return 'Contains unsafe directives';
                    }
                    return null;
                }
            },
            'referrer-policy': {
                name: 'Referrer-Policy',
                validator: (value) => {
                    const secure = ['no-referrer', 'no-referrer-when-downgrade', 'same-origin', 'strict-origin'];
                    if (!secure.some(policy => value.includes(policy))) {
                        return 'Should use a secure referrer policy';
                    }
                    return null;
                }
            },
            'permissions-policy': {
                name: 'Permissions-Policy',
                validator: (value) => value ? null : 'Should define permissions'
            }
        };
        
        // Check each header
        for (const [header, config] of Object.entries(requiredHeaders)) {
            const value = this.headers.get(header);
            
            if (!value) {
                security.missing.push({
                    header: config.name,
                    impact: 'Security vulnerability'
                });
                security.score -= 15;
            } else {
                const error = config.validator(value);
                if (error) {
                    security.misconfigured.push({
                        header: config.name,
                        value,
                        issue: error
                    });
                    security.score -= 10;
                } else {
                    security.present.push({
                        header: config.name,
                        value
                    });
                }
            }
        }
        
        // Check for dangerous headers
        this.checkDangerousHeaders(security);
        
        security.score = Math.max(0, security.score);
        return security;
    }
    
    // Check for dangerous headers
    checkDangerousHeaders(security) {
        const dangerous = {
            'x-powered-by': 'Reveals server technology',
            'server': 'Should not reveal version numbers',
            'x-aspnet-version': 'Reveals ASP.NET version',
            'x-aspnetmvc-version': 'Reveals ASP.NET MVC version',
            'x-backend-server': 'Reveals internal infrastructure',
            'x-forwarded-host': 'May reveal internal hostnames',
            'x-runtime': 'Reveals runtime information',
            'x-version': 'Reveals version information',
            'x-debug': 'Debug headers should not be in production'
        };
        
        for (const [header, issue] of Object.entries(dangerous)) {
            const value = this.headers.get(header);
            if (value) {
                // Special handling for Server header
                if (header === 'server' && !this.hasVersionInfo(value)) {
                    continue;
                }
                
                this.issues.push({
                    severity: 'medium',
                    category: 'security',
                    header,
                    value,
                    issue
                });
                security.score -= 5;
            }
        }
    }
    
    // Check if value contains version information
    hasVersionInfo(value) {
        return /\d+\.\d+/.test(value) || /\/([\d.]+)/.test(value);
    }
    
    // Analyze caching headers
    analyzeCachingHeaders() {
        const caching = {
            strategy: 'none',
            ttl: 0,
            directives: [],
            issues: []
        };
        
        // Cache-Control
        const cacheControl = this.headers.get('cache-control');
        if (cacheControl) {
            caching.directives = cacheControl.split(',').map(d => d.trim());
            
            // Parse max-age
            const maxAge = cacheControl.match(/max-age=(\d+)/);
            if (maxAge) {
                caching.ttl = parseInt(maxAge[1]);
            }
            
            // Determine strategy
            if (cacheControl.includes('no-store')) {
                caching.strategy = 'no-store';
            } else if (cacheControl.includes('no-cache')) {
                caching.strategy = 'no-cache';
            } else if (cacheControl.includes('public')) {
                caching.strategy = 'public';
            } else if (cacheControl.includes('private')) {
                caching.strategy = 'private';
            }
            
            // Check for issues
            if (cacheControl.includes('public') && this.headers.get('set-cookie')) {
                caching.issues.push({
                    severity: 'high',
                    issue: 'Public cache with Set-Cookie header',
                    impact: 'Session cookies may be cached'
                });
            }
        }
        
        // ETag
        const etag = this.headers.get('etag');
        if (etag) {
            caching.etag = etag;
            caching.hasValidation = true;
        }
        
        // Last-Modified
        const lastModified = this.headers.get('last-modified');
        if (lastModified) {
            caching.lastModified = lastModified;
            caching.hasValidation = true;
        }
        
        // Expires (legacy)
        const expires = this.headers.get('expires');
        if (expires && !cacheControl) {
            caching.expires = expires;
            caching.strategy = 'expires';
        }
        
        // Vary
        const vary = this.headers.get('vary');
        if (vary) {
            caching.vary = vary.split(',').map(v => v.trim());
            
            if (vary === '*') {
                caching.issues.push({
                    severity: 'medium',
                    issue: 'Vary: * prevents caching',
                    impact: 'Response cannot be cached'
                });
            }
        }
        
        return caching;
    }
    
    // Analyze compression headers
    analyzeCompressionHeaders() {
        const compression = {
            enabled: false,
            encoding: null,
            issues: []
        };
        
        const contentEncoding = this.headers.get('content-encoding');
        if (contentEncoding) {
            compression.enabled = true;
            compression.encoding = contentEncoding;
            
            // Check for multiple encodings
            if (contentEncoding.includes(',')) {
                compression.multiple = contentEncoding.split(',').map(e => e.trim());
            }
        }
        
        // Check Content-Type for compressible resources
        const contentType = this.headers.get('content-type');
        if (contentType && this.isCompressible(contentType) && !compression.enabled) {
            compression.issues.push({
                severity: 'medium',
                issue: 'Compressible resource served uncompressed',
                contentType,
                impact: 'Larger transfer size'
            });
        }
        
        // Check for double compression
        if (compression.enabled && contentType && contentType.includes('gzip')) {
            compression.issues.push({
                severity: 'low',
                issue: 'Possible double compression',
                impact: 'CPU overhead without benefit'
            });
        }
        
        return compression;
    }
    
    // Check if content type is compressible
    isCompressible(contentType) {
        const compressible = [
            'text/', 'application/json', 'application/javascript',
            'application/xml', 'application/svg+xml', 'application/x-font',
            'application/vnd.ms-fontobject'
        ];
        
        return compressible.some(type => contentType.includes(type));
    }
    
    // Analyze server headers
    analyzeServerHeaders() {
        const server = {
            software: null,
            timing: null,
            backend: null,
            issues: []
        };
        
        // Server header
        const serverHeader = this.headers.get('server');
        if (serverHeader) {
            server.software = serverHeader;
            
            // Parse server info
            const parsed = this.parseServerHeader(serverHeader);
            server.parsed = parsed;
            
            if (parsed.version) {
                server.issues.push({
                    severity: 'medium',
                    issue: 'Server version exposed',
                    version: parsed.version,
                    impact: 'Attackers can target known vulnerabilities'
                });
            }
        }
        
        // Server-Timing
        const serverTiming = this.headers.get('server-timing');
        if (serverTiming) {
            server.timing = this.parseServerTiming(serverTiming);
        }
        
        // Backend indicators
        const backendHeaders = [
            'x-backend-server',
            'x-served-by',
            'x-server-id',
            'x-proxy-id'
        ];
        
        backendHeaders.forEach(header => {
            const value = this.headers.get(header);
            if (value) {
                if (!server.backend) server.backend = {};
                server.backend[header] = value;
            }
        });
        
        return server;
    }
    
    // Parse server header
    parseServerHeader(header) {
        const parsed = {
            name: null,
            version: null,
            modules: []
        };
        
        // Common patterns
        const patterns = {
            apache: /Apache(?:\/(\S+))?/i,
            nginx: /nginx(?:\/(\S+))?/i,
            iis: /Microsoft-IIS(?:\/(\S+))?/i,
            nodejs: /Node\.js(?:\/(\S+))?/i,
            express: /Express/i
        };
        
        for (const [name, pattern] of Object.entries(patterns)) {
            const match = header.match(pattern);
            if (match) {
                parsed.name = name;
                if (match[1]) {
                    parsed.version = match[1];
                }
                break;
            }
        }
        
        // Parse modules (e.g., Apache modules)
        const modules = header.match(/\(([^)]+)\)/);
        if (modules) {
            parsed.modules = modules[1].split(' ');
        }
        
        return parsed;
    }
    
    // Parse Server-Timing header
    parseServerTiming(header) {
        const timings = [];
        
        // Parse each timing entry
        const entries = header.split(',');
        entries.forEach(entry => {
            const match = entry.match(/(\w+)(?:;(?:dur=(\d+(?:\.\d+)?)))?(?:;desc="([^"]+)")?/);
            if (match) {
                timings.push({
                    name: match[1],
                    duration: match[2] ? parseFloat(match[2]) : null,
                    description: match[3] || null
                });
            }
        });
        
        return timings;
    }
    
    // Analyze custom headers
    analyzeCustomHeaders() {
        const custom = {
            headers: [],
            patterns: {
                api: [],
                debug: [],
                internal: [],
                tracking: []
            }
        };
        
        // Define patterns
        const patterns = {
            api: /^x-api-|api-version|x-ratelimit/i,
            debug: /debug|trace|profile/i,
            internal: /internal|private|backend/i,
            tracking: /request-id|trace-id|correlation-id/i
        };
        
        // Check all headers
        for (const [header, value] of this.headers) {
            // Skip standard headers
            if (this.isStandardHeader(header)) continue;
            
            // Categorize custom headers
            for (const [category, pattern] of Object.entries(patterns)) {
                if (pattern.test(header)) {
                    custom.patterns[category].push({
                        header,
                        value
                    });
                }
            }
            
            // Add to custom list
            if (header.startsWith('x-') || !this.isCommonHeader(header)) {
                custom.headers.push({
                    header,
                    value,
                    category: this.categorizeHeader(header)
                });
            }
        }
        
        return custom;
    }
    
    // Check if header is standard
    isStandardHeader(header) {
        const standard = [
            'cache-control', 'content-type', 'content-length', 'date',
            'etag', 'expires', 'last-modified', 'location', 'server',
            'set-cookie', 'vary', 'content-encoding', 'transfer-encoding'
        ];
        
        return standard.includes(header);
    }
    
    // Check if header is common
    isCommonHeader(header) {
        const common = [
            'accept-ranges', 'age', 'allow', 'content-language',
            'content-location', 'content-range', 'pragma', 'retry-after',
            'strict-transport-security', 'x-content-type-options',
            'x-frame-options', 'x-xss-protection'
        ];
        
        return common.includes(header);
    }
    
    // Categorize custom header
    categorizeHeader(header) {
        if (header.includes('api')) return 'api';
        if (header.includes('limit')) return 'rate-limiting';
        if (header.includes('id')) return 'tracking';
        if (header.includes('time')) return 'timing';
        return 'other';
    }
    
    // Calculate overall score
    calculateScore() {
        let score = 100;
        
        // Security impact
        const securityScore = this.analyzeSecurityHeaders().score;
        score = Math.min(score, securityScore);
        
        // Issues impact
        this.issues.forEach(issue => {
            switch (issue.severity) {
                case 'high':
                    score -= 20;
                    break;
                case 'medium':
                    score -= 10;
                    break;
                case 'low':
                    score -= 5;
                    break;
            }
        });
        
        return Math.max(0, score);
    }
    
    // Generate recommendations
    generateRecommendations() {
        const recommendations = [];
        
        // Security recommendations
        const security = this.analyzeSecurityHeaders();
        
        if (security.missing.length > 0) {
            recommendations.push({
                category: 'security',
                priority: 'high',
                title: 'Add missing security headers',
                headers: security.missing,
                implementation: this.generateSecurityHeadersConfig()
            });
        }
        
        if (security.misconfigured.length > 0) {
            recommendations.push({
                category: 'security',
                priority: 'medium',
                title: 'Fix misconfigured security headers',
                headers: security.misconfigured
            });
        }
        
        // Caching recommendations
        const caching = this.analyzeCachingHeaders();
        
        if (caching.strategy === 'none') {
            recommendations.push({
                category: 'performance',
                priority: 'medium',
                title: 'Implement caching strategy',
                suggestion: 'Add Cache-Control headers for better performance'
            });
        }
        
        // Compression recommendations
        const compression = this.analyzeCompressionHeaders();
        
        if (!compression.enabled) {
            recommendations.push({
                category: 'performance',
                priority: 'medium',
                title: 'Enable compression',
                suggestion: 'Use gzip or brotli compression for text resources'
            });
        }
        
        // Server recommendations
        const server = this.analyzeServerHeaders();
        
        if (server.issues.length > 0) {
            recommendations.push({
                category: 'security',
                priority: 'medium',
                title: 'Hide server information',
                issues: server.issues
            });
        }
        
        return recommendations;
    }
    
    // Generate security headers configuration
    generateSecurityHeadersConfig() {
        return {
            nginx: `# Nginx security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;`,
            
            apache: `# Apache security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"`,
            
            nodejs: `// Express.js security headers
const helmet = require('helmet');

app.use(helmet({
    strictTransportSecurity: {
        maxAge: 31536000,
        includeSubDomains: true,
        preload: true
    },
    contentSecurityPolicy: {
        directives: {
            defaultSrc: ["'self'"],
            scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
            styleSrc: ["'self'", "'unsafe-inline'"]
        }
    }
}));`
        };
    }
}

// Analyze current page
const analyzer = new ResponseHeaderAnalyzer();
analyzer.analyzeCurrentPage().then(analysis => {
    console.log('Header Analysis:', analysis);
});

Header Configuration Generator

Generate optimal header configurations:

// Header Configuration Generator
class HeaderConfigGenerator {
    constructor() {
        this.config = {
            security: {},
            caching: {},
            compression: {},
            custom: {}
        };
    }
    
    // Generate complete configuration
    generateConfiguration(options = {}) {
        const config = {
            nginx: this.generateNginxConfig(options),
            apache: this.generateApacheConfig(options),
            express: this.generateExpressConfig(options),
            cloudflare: this.generateCloudflareConfig(options),
            vercel: this.generateVercelConfig(options),
            netlify: this.generateNetlifyConfig(options)
        };
        
        return config;
    }
    
    // Generate Nginx configuration
    generateNginxConfig(options) {
        const { 
            environment = 'production',
            csp = true,
            hsts = true,
            caching = true,
            compression = true
        } = options;
        
        let config = `# Nginx Headers Configuration
# Generated: ${new Date().toISOString()}

`;
        
        // Security headers
        if (environment === 'production') {
            config += `# Security Headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" always;

`;
            
            if (hsts) {
                config += `# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

`;
            }
            
            if (csp) {
                config += `# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;

`;
            }
        }
        
        // Hide server version
        config += `# Hide server information
server_tokens off;
more_clear_headers 'Server';
more_clear_headers 'X-Powered-By';

`;
        
        // Compression
        if (compression) {
            config += `# Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss application/x-font-ttf font/opentype image/svg+xml image/x-icon;
gzip_disable "msie6";
gzip_comp_level 6;

# Brotli compression (if available)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss application/x-font-ttf font/opentype image/svg+xml image/x-icon;

`;
        }
        
        // Caching
        if (caching) {
            config += `# Caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.(html|xml|json)$ {
    expires 1h;
    add_header Cache-Control "public, must-revalidate";
}

# API responses
location /api/ {
    add_header Cache-Control "no-cache, no-store, must-revalidate";
    add_header Pragma "no-cache";
    add_header Expires "0";
}

`;
        }
        
        // Custom headers
        config += `# Custom headers
add_header X-Request-ID $request_id always;
add_header X-Content-Type-Options "nosniff" always;

# CORS (if needed)
# add_header Access-Control-Allow-Origin "https://example.com" always;
# add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
# add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
# add_header Access-Control-Max-Age "86400" always;
`;
        
        return config;
    }
    
    // Generate Apache configuration
    generateApacheConfig(options) {
        const { 
            environment = 'production',
            csp = true,
            hsts = true,
            caching = true,
            compression = true
        } = options;
        
        let config = `# Apache Headers Configuration
# Generated: ${new Date().toISOString()}

<IfModule mod_headers.c>
`;
        
        // Security headers
        if (environment === 'production') {
            config += `    # Security Headers
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
    
`;
            
            if (hsts) {
                config += `    # HSTS
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    
`;
            }
            
            if (csp) {
                config += `    # Content Security Policy
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';"
    
`;
            }
        }
        
        // Hide server information
        config += `    # Hide server information
    Header always unset Server
    Header unset X-Powered-By
    ServerTokens Prod
    ServerSignature Off
</IfModule>

`;
        
        // Compression
        if (compression) {
            config += `# Compression
<IfModule mod_deflate.c>
    # Compress HTML, CSS, JavaScript, Text, XML and fonts
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/json
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
    AddOutputFilterByType DEFLATE application/x-font
    AddOutputFilterByType DEFLATE application/x-font-opentype
    AddOutputFilterByType DEFLATE application/x-font-otf
    AddOutputFilterByType DEFLATE application/x-font-truetype
    AddOutputFilterByType DEFLATE application/x-font-ttf
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE font/opentype
    AddOutputFilterByType DEFLATE font/otf
    AddOutputFilterByType DEFLATE font/ttf
    AddOutputFilterByType DEFLATE image/svg+xml
    AddOutputFilterByType DEFLATE image/x-icon
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/xml
    
    # Remove browser bugs
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
    Header append Vary User-Agent
</IfModule>

`;
        }
        
        // Caching
        if (caching) {
            config += `# Caching
<IfModule mod_expires.c>
    ExpiresActive On
    
    # Images
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"
    ExpiresByType image/x-icon "access plus 1 year"
    
    # CSS and JavaScript
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType text/javascript "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    
    # Web fonts
    ExpiresByType font/ttf "access plus 1 year"
    ExpiresByType font/otf "access plus 1 year"
    ExpiresByType font/woff "access plus 1 year"
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType application/font-woff "access plus 1 year"
    
    # HTML and XML
    ExpiresByType text/html "access plus 0 seconds"
    ExpiresByType application/xml "access plus 0 seconds"
    ExpiresByType application/json "access plus 0 seconds"
</IfModule>

<IfModule mod_headers.c>
    # Cache-Control headers
    <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf|woff|woff2)$">
        Header set Cache-Control "public, immutable, max-age=31536000"
    </FilesMatch>
    
    # Don't cache HTML
    <FilesMatch "\.(html|htm|xml|json)$">
        Header set Cache-Control "no-cache, no-store, must-revalidate"
        Header set Pragma "no-cache"
        Header set Expires "0"
    </FilesMatch>
</IfModule>
`;
        }
        
        return config;
    }
    
    // Generate Express.js configuration
    generateExpressConfig(options) {
        const { 
            environment = 'production',
            csp = true,
            hsts = true,
            caching = true,
            compression = true
        } = options;
        
        let config = `// Express.js Headers Configuration
// Generated: ${new Date().toISOString()}

const express = require('express');
const helmet = require('helmet');
const compression = require('compression');

const app = express();

`;
        
        // Compression
        if (compression) {
            config += `// Enable compression
app.use(compression({
    filter: (req, res) => {
        if (req.headers['x-no-compression']) {
            return false;
        }
        return compression.filter(req, res);
    },
    level: 6
}));

`;
        }
        
        // Security headers with Helmet
        config += `// Security headers
app.use(helmet({
    contentSecurityPolicy: ${csp ? `{
        directives: {
            defaultSrc: ["'self'"],
            scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://www.google-analytics.com"],
            styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
            fontSrc: ["'self'", "https://fonts.gstatic.com"],
            imgSrc: ["'self'", "data:", "https:"],
            connectSrc: ["'self'", "https://api.example.com"],
            frameAncestors: ["'none'"],
            baseUri: ["'self'"],
            formAction: ["'self'"]
        }
    }` : 'false'},
    hsts: ${hsts ? `{
        maxAge: 31536000,
        includeSubDomains: true,
        preload: true
    }` : 'false'}
}));

// Additional security headers
app.use((req, res, next) => {
    res.setHeader('X-Content-Type-Options', 'nosniff');
    res.setHeader('X-Frame-Options', 'SAMEORIGIN');
    res.setHeader('X-XSS-Protection', '1; mode=block');
    res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
    res.setHeader('Permissions-Policy', 'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()');
    
    // Remove X-Powered-By
    res.removeHeader('X-Powered-By');
    
    next();
});

`;
        
        // Caching
        if (caching) {
            config += `// Caching middleware
const setCache = (duration) => {
    return (req, res, next) => {
        if (req.method === 'GET') {
            res.set('Cache-Control', \`public, max-age=\${duration}\`);
        } else {
            res.set('Cache-Control', 'no-store');
        }
        next();
    };
};

// Static files caching
app.use('/static', setCache(31536000), express.static('public'));

// API no-cache
app.use('/api', (req, res, next) => {
    res.set({
        'Cache-Control': 'no-cache, no-store, must-revalidate',
        'Pragma': 'no-cache',
        'Expires': '0'
    });
    next();
});

`;
        }
        
        // Custom headers
        config += `// Custom headers
app.use((req, res, next) => {
    // Request ID for tracking
    const requestId = req.headers['x-request-id'] || generateRequestId();
    res.setHeader('X-Request-ID', requestId);
    
    // Server timing
    res.setHeader('Server-Timing', \`app;dur=\${Date.now() - req.startTime}\`);
    
    next();
});

// CORS configuration (if needed)
/*
const cors = require('cors');
app.use(cors({
    origin: 'https://example.com',
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true,
    maxAge: 86400
}));
*/

function generateRequestId() {
    return Math.random().toString(36).substr(2, 9);
}

module.exports = app;`;
        
        return config;
    }
    
    // Generate Cloudflare Workers configuration
    generateCloudflareConfig(options) {
        return `// Cloudflare Workers Headers
addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
    const response = await fetch(request);
    
    // Create new response with modified headers
    const newHeaders = new Headers(response.headers);
    
    // Security headers
    newHeaders.set('X-Content-Type-Options', 'nosniff');
    newHeaders.set('X-Frame-Options', 'SAMEORIGIN');
    newHeaders.set('X-XSS-Protection', '1; mode=block');
    newHeaders.set('Referrer-Policy', 'strict-origin-when-cross-origin');
    newHeaders.set('Permissions-Policy', 'accelerometer=(), camera=(), geolocation=()');
    
    // HSTS (if HTTPS)
    if (request.url.startsWith('https://')) {
        newHeaders.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
    }
    
    // CSP
    newHeaders.set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';");
    
    // Remove sensitive headers
    newHeaders.delete('X-Powered-By');
    newHeaders.delete('Server');
    
    // Add custom headers
    newHeaders.set('X-Request-ID', crypto.randomUUID());
    
    return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: newHeaders
    });
}`;
    }
    
    // Generate Vercel configuration
    generateVercelConfig(options) {
        return `{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "X-Content-Type-Options",
          "value": "nosniff"
        },
        {
          "key": "X-Frame-Options",
          "value": "SAMEORIGIN"
        },
        {
          "key": "X-XSS-Protection",
          "value": "1; mode=block"
        },
        {
          "key": "Referrer-Policy",
          "value": "strict-origin-when-cross-origin"
        },
        {
          "key": "Permissions-Policy",
          "value": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
        }
      ]
    },
    {
      "source": "/(.*)",
      "has": [
        {
          "type": "host",
          "value": "(?<protocol>https):\\/\\/(.*)"
        }
      ],
      "headers": [
        {
          "key": "Strict-Transport-Security",
          "value": "max-age=31536000; includeSubDomains; preload"
        }
      ]
    },
    {
      "source": "/api/(.*)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "no-cache, no-store, must-revalidate"
        }
      ]
    },
    {
      "source": "/static/(.*)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=31536000, immutable"
        }
      ]
    }
  ]
}`;
    }
    
    // Generate Netlify configuration
    generateNetlifyConfig(options) {
        return `# Netlify Headers Configuration (_headers file)

/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: SAMEORIGIN
  X-XSS-Protection: 1; mode=block
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
  Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';

https://*
  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

/api/*
  Cache-Control: no-cache, no-store, must-revalidate
  Pragma: no-cache
  Expires: 0

/static/*
  Cache-Control: public, max-age=31536000, immutable

/*.js
  Cache-Control: public, max-age=31536000, immutable
  Content-Type: application/javascript; charset=UTF-8

/*.css
  Cache-Control: public, max-age=31536000, immutable
  Content-Type: text/css; charset=UTF-8

/*.woff2
  Cache-Control: public, max-age=31536000, immutable
  Content-Type: font/woff2
  Access-Control-Allow-Origin: *`;
    }
}

// Generate configurations
const generator = new HeaderConfigGenerator();
const configs = generator.generateConfiguration({
    environment: 'production',
    csp: true,
    hsts: true,
    caching: true,
    compression: true
});

console.log('Header Configurations:', configs);

Header Testing Suite

Test header configurations:

// Header Testing Suite
class HeaderTester {
    constructor() {
        this.tests = [];
        this.results = {
            passed: 0,
            failed: 0,
            warnings: 0
        };
    }
    
    // Run all header tests
    async runTests(url) {
        console.log(`Testing headers for: ${url}`);
        
        const tests = [
            this.testSecurityHeaders(url),
            this.testCaching(url),
            this.testCompression(url),
            this.testCORS(url),
            this.testServerInfo(url),
            this.testCustomHeaders(url)
        ];
        
        const results = await Promise.all(tests);
        
        // Compile results
        const report = {
            url,
            timestamp: new Date().toISOString(),
            tests: results.flat(),
            summary: this.results,
            score: this.calculateTestScore()
        };
        
        return report;
    }
    
    // Test security headers
    async testSecurityHeaders(url) {
        const tests = [];
        
        try {
            const response = await fetch(url, { method: 'HEAD' });
            const headers = Object.fromEntries(response.headers.entries());
            
            // Test each security header
            const securityTests = {
                'strict-transport-security': {
                    name: 'HSTS',
                    test: (value) => {
                        if (!value) return { passed: false, error: 'Missing HSTS header' };
                        const maxAge = value.match(/max-age=(\d+)/);
                        if (!maxAge || parseInt(maxAge[1]) < 31536000) {
                            return { passed: false, error: 'HSTS max-age too short' };
                        }
                        return { passed: true };
                    }
                },
                'x-content-type-options': {
                    name: 'X-Content-Type-Options',
                    test: (value) => ({
                        passed: value === 'nosniff',
                        error: value ? 'Invalid value' : 'Missing header'
                    })
                },
                'x-frame-options': {
                    name: 'X-Frame-Options',
                    test: (value) => ({
                        passed: ['DENY', 'SAMEORIGIN'].includes(value),
                        error: value ? 'Invalid value' : 'Missing header'
                    })
                },
                'content-security-policy': {
                    name: 'CSP',
                    test: (value) => {
                        if (!value) return { passed: false, error: 'Missing CSP header' };
                        if (value.includes('unsafe-inline') && value.includes('unsafe-eval')) {
                            return { passed: false, warning: 'CSP contains unsafe directives' };
                        }
                        return { passed: true };
                    }
                }
            };
            
            for (const [header, config] of Object.entries(securityTests)) {
                const value = headers[header];
                const result = config.test(value);
                
                tests.push({
                    category: 'security',
                    name: config.name,
                    header,
                    value: value || 'not set',
                    ...result
                });
                
                if (result.passed) this.results.passed++;
                else if (result.warning) this.results.warnings++;
                else this.results.failed++;
            }
            
        } catch (error) {
            tests.push({
                category: 'security',
                name: 'Security Headers Test',
                error: error.message,
                passed: false
            });
            this.results.failed++;
        }
        
        return tests;
    }
    
    // Test caching configuration
    async testCaching(url) {
        const tests = [];
        
        try {
            // Test different resource types
            const resources = [
                { path: '/', type: 'html', expectedCache: 'no-cache' },
                { path: '/static/image.jpg', type: 'image', expectedCache: 'max-age=31536000' },
                { path: '/api/data', type: 'api', expectedCache: 'no-store' }
            ];
            
            for (const resource of resources) {
                const testUrl = new URL(resource.path, url).href;
                
                try {
                    const response = await fetch(testUrl, { method: 'HEAD' });
                    const cacheControl = response.headers.get('cache-control');
                    
                    tests.push({
                        category: 'caching',
                        name: `Cache test: ${resource.type}`,
                        url: testUrl,
                        cacheControl,
                        passed: this.validateCacheControl(cacheControl, resource.expectedCache)
                    });
                    
                } catch (e) {
                    // Resource might not exist
                    tests.push({
                        category: 'caching',
                        name: `Cache test: ${resource.type}`,
                        skipped: true,
                        reason: 'Resource not found'
                    });
                }
            }
            
        } catch (error) {
            tests.push({
                category: 'caching',
                error: error.message,
                passed: false
            });
        }
        
        return tests;
    }
    
    // Validate cache control
    validateCacheControl(actual, expected) {
        if (!actual) return false;
        
        if (expected === 'no-cache') {
            return actual.includes('no-cache') || actual.includes('no-store');
        }
        
        if (expected === 'no-store') {
            return actual.includes('no-store');
        }
        
        if (expected.includes('max-age')) {
            return actual.includes('max-age');
        }
        
        return true;
    }
    
    // Test compression
    async testCompression(url) {
        const tests = [];
        
        try {
            const response = await fetch(url, {
                headers: {
                    'Accept-Encoding': 'gzip, deflate, br'
                }
            });
            
            const encoding = response.headers.get('content-encoding');
            const contentType = response.headers.get('content-type');
            
            tests.push({
                category: 'compression',
                name: 'Compression test',
                encoding: encoding || 'none',
                contentType,
                passed: encoding && ['gzip', 'deflate', 'br'].includes(encoding),
                warning: !encoding && this.isCompressible(contentType) ? 
                    'Compressible content served uncompressed' : null
            });
            
        } catch (error) {
            tests.push({
                category: 'compression',
                error: error.message,
                passed: false
            });
        }
        
        return tests;
    }
    
    // Check if content is compressible
    isCompressible(contentType) {
        if (!contentType) return false;
        
        const compressible = ['text/', 'application/json', 'application/javascript', 'application/xml'];
        return compressible.some(type => contentType.includes(type));
    }
    
    // Test CORS configuration
    async testCORS(url) {
        const tests = [];
        
        try {
            // Test preflight request
            const response = await fetch(url, {
                method: 'OPTIONS',
                headers: {
                    'Origin': 'https://example.com',
                    'Access-Control-Request-Method': 'POST'
                }
            });
            
            const corsHeaders = {
                'access-control-allow-origin': response.headers.get('access-control-allow-origin'),
                'access-control-allow-methods': response.headers.get('access-control-allow-methods'),
                'access-control-allow-headers': response.headers.get('access-control-allow-headers'),
                'access-control-max-age': response.headers.get('access-control-max-age')
            };
            
            tests.push({
                category: 'cors',
                name: 'CORS configuration',
                headers: corsHeaders,
                passed: corsHeaders['access-control-allow-origin'] !== null,
                info: 'CORS headers present'
            });
            
        } catch (error) {
            tests.push({
                category: 'cors',
                name: 'CORS test',
                skipped: true,
                reason: 'Could not test CORS'
            });
        }
        
        return tests;
    }
    
    // Test server information leakage
    async testServerInfo(url) {
        const tests = [];
        
        try {
            const response = await fetch(url, { method: 'HEAD' });
            
            const sensitiveHeaders = [
                'server',
                'x-powered-by',
                'x-aspnet-version',
                'x-aspnetmvc-version',
                'x-backend-server'
            ];
            
            sensitiveHeaders.forEach(header => {
                const value = response.headers.get(header);
                if (value) {
                    tests.push({
                        category: 'server-info',
                        name: `Information leakage: ${header}`,
                        header,
                        value,
                        passed: false,
                        error: 'Sensitive information exposed'
                    });
                    this.results.failed++;
                }
            });
            
            if (tests.length === 0) {
                tests.push({
                    category: 'server-info',
                    name: 'Server information',
                    passed: true,
                    info: 'No sensitive headers found'
                });
                this.results.passed++;
            }
            
        } catch (error) {
            tests.push({
                category: 'server-info',
                error: error.message,
                passed: false
            });
        }
        
        return tests;
    }
    
    // Test custom headers
    async testCustomHeaders(url) {
        const tests = [];
        
        try {
            const response = await fetch(url);
            const headers = Object.fromEntries(response.headers.entries());
            
            // Look for custom headers
            const customHeaders = Object.entries(headers)
                .filter(([key]) => key.startsWith('x-') && 
                    !['x-content-type-options', 'x-frame-options', 'x-xss-protection'].includes(key));
            
            if (customHeaders.length > 0) {
                tests.push({
                    category: 'custom',
                    name: 'Custom headers found',
                    headers: Object.fromEntries(customHeaders),
                    passed: true,
                    info: `${customHeaders.length} custom headers detected`
                });
            }
            
        } catch (error) {
            tests.push({
                category: 'custom',
                error: error.message,
                passed: false
            });
        }
        
        return tests;
    }
    
    // Calculate test score
    calculateTestScore() {
        const total = this.results.passed + this.results.failed + this.results.warnings;
        if (total === 0) return 0;
        
        const score = ((this.results.passed + (this.results.warnings * 0.5)) / total) * 100;
        return Math.round(score);
    }
}

// Run header tests
const tester = new HeaderTester();
tester.runTests(window.location.origin).then(report => {
    console.log('Header Test Report:', report);
});

Best Practices for Response Headers

  1. Hide Server Information: Remove version numbers and technology indicators
  2. Implement Security Headers: HSTS, CSP, X-Frame-Options, etc.
  3. Configure Caching Properly: Different strategies for different resources
  4. Enable Compression: Gzip/Brotli for text resources
  5. Set Correct Content-Types: Prevent MIME sniffing attacks
  6. Use HTTPS Everywhere: Force secure connections
  7. Implement CORS Carefully: Only allow necessary origins
  8. Add Request Tracking: X-Request-ID for debugging
  9. Monitor Header Changes: Headers can reveal infrastructure changes
  10. Test Regularly: Automated header testing in CI/CD

Common Header Mistakes

  • Version Disclosure: Apache/2.4.41, nginx/1.17.0 in Server header
  • Technology Leakage: X-Powered-By: PHP/7.2.24
  • Missing Security Headers: No HSTS, CSP, or X-Frame-Options
  • Cache Confusion: Private data with public cache headers
  • CORS Wildcards: Access-Control-Allow-Origin: *
  • Debug Headers: X-Debug-Token in production
  • Inconsistent Headers: Different headers for same resource type
  • Header Injection: Reflecting user input in headers
  • Outdated Headers: Using deprecated security headers
  • No Compression: Serving large text files uncompressed

Remember: Response headers are your application's metadata. Configure them carefully—they can either strengthen your security posture or expose your vulnerabilities to the world.