Dynamic CSP Generation

Dynamic CSP Generation

Modern applications often require dynamic CSP policies based on user context, feature flags, or runtime configuration. Implementing dynamic CSP generation provides flexibility while maintaining security.

// Dynamic CSP Generator
class DynamicCSPGenerator {
    constructor(basePolicy) {
        this.basePolicy = basePolicy;
        this.contextualPolicies = new Map();
    }
    
    registerContextualPolicy(context, modifications) {
        this.contextualPolicies.set(context, modifications);
    }
    
    generatePolicy(context = {}) {
        // Start with base policy
        let policy = JSON.parse(JSON.stringify(this.basePolicy));
        
        // Apply contextual modifications
        if (context.userRole === 'admin') {
            // Admins might need additional sources for admin panels
            policy['script-src'].push('https://admin-assets.example.com');
        }
        
        if (context.features?.analytics) {
            // Add analytics endpoints
            policy['script-src'].push('https://www.google-analytics.com');
            policy['connect-src'].push('https://www.google-analytics.com');
            policy['img-src'].push('https://www.google-analytics.com');
        }
        
        if (context.features?.chat) {
            // Add chat widget sources
            policy['frame-src'] = policy['frame-src'] || ["'self'"];
            policy['frame-src'].push('https://chat.example.com');
            policy['connect-src'].push('wss://chat.example.com');
        }
        
        if (context.environment === 'development') {
            // Relax policies for development
            policy['script-src'].push("'unsafe-eval'"); // For webpack dev server
            policy['connect-src'].push('ws://localhost:*'); // For hot reload
        }
        
        return this.formatPolicy(policy);
    }
    
    formatPolicy(policy) {
        return Object.entries(policy)
            .filter(([_, values]) => values && values.length > 0)
            .map(([directive, values]) => `${directive} ${values.join(' ')}`)
            .join('; ');
    }
}

// Usage example
const cspGenerator = new DynamicCSPGenerator({
    'default-src': ["'self'"],
    'script-src': ["'self'"],
    'style-src': ["'self'"],
    'img-src': ["'self'", 'data:'],
    'connect-src': ["'self'"]
});

// Express middleware using dynamic CSP
app.use((req, res, next) => {
    const context = {
        userRole: req.user?.role,
        features: {
            analytics: req.cookies.analyticsConsent === 'true',
            chat: req.user?.premiumFeatures?.includes('chat')
        },
        environment: process.env.NODE_ENV
    };
    
    const policy = cspGenerator.generatePolicy(context);
    res.setHeader('Content-Security-Policy', policy);
    next();
});