Combining Advanced Patterns

Combining Advanced Patterns

Effective CSP implementation often requires combining multiple advanced patterns:

// Advanced CSP Pattern Combinator
class AdvancedCSPCombinator {
  constructor() {
    this.nonceManager = new NonceManager();
    this.hashManager = new HashBasedCSP();
    this.strictDynamic = new StrictDynamicCSP();
  }
  
  // Hybrid approach: Nonces for dynamic, hashes for static
  generateHybridPolicy(options = {}) {
    const nonce = this.nonceManager.generateNonce();
    
    const policy = {
      'default-src': ["'none'"],
      'script-src': [
        "'self'",
        `'nonce-${nonce}'`,
        "'strict-dynamic'",
        ...this.hashManager.hashes.scripts
      ],
      'style-src': [
        "'self'",
        `'nonce-${nonce}'`,
        ...this.hashManager.hashes.styles
      ],
      'img-src': ["'self'", 'data:', 'https:'],
      'font-src': ["'self'", 'https://fonts.gstatic.com'],
      'connect-src': ["'self'"],
      'worker-src': ["'self'", 'blob:'],
      'frame-ancestors': ["'none'"],
      'base-uri': ["'none'"],
      'form-action': ["'self'"],
      'upgrade-insecure-requests': ['']
    };
    
    // Add backward compatibility
    if (options.backwardCompatible) {
      policy['script-src'].push('https:', "'unsafe-inline'");
    }
    
    return {
      nonce,
      policy: this.formatPolicy(policy)
    };
  }
  
  // Progressive enhancement strategy
  implementProgressiveEnhancement() {
    return {
      // Level 1: Basic CSP (wide browser support)
      level1: {
        policy: "default-src 'self'; script-src 'self' 'unsafe-inline' https:; style-src 'self' 'unsafe-inline'",
        support: 'CSP 1.0+'
      },
      
      // Level 2: Nonce-based (modern browsers)
      level2: {
        policy: (nonce) => `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'nonce-${nonce}'`,
        support: 'CSP 2.0+'
      },
      
      // Level 3: Strict-dynamic (latest browsers)
      level3: {
        policy: (nonce) => `default-src 'none'; script-src 'nonce-${nonce}' 'strict-dynamic'; style-src 'self' 'nonce-${nonce}'`,
        support: 'CSP 3.0+'
      }
    };
  }
  
  // Feature detection for CSP support
  generateFeatureDetectionScript() {
    return `
      (function() {
        const cspSupport = {
          basic: false,
          nonce: false,
          hash: false,
          strictDynamic: false,
          reportTo: false
        };
        
        // Test basic CSP support
        try {
          const meta = document.createElement('meta');
          meta.httpEquiv = 'Content-Security-Policy';
          meta.content = "default-src 'none'";
          document.head.appendChild(meta);
          document.head.removeChild(meta);
          cspSupport.basic = true;
        } catch (e) {}
        
        // Test nonce support
        if (document.currentScript && document.currentScript.nonce) {
          cspSupport.nonce = true;
        }
        
        // Test strict-dynamic support
        try {
          const testPolicy = "script-src 'strict-dynamic' 'nonce-test'";
          cspSupport.strictDynamic = true;
        } catch (e) {}
        
        // Store results
        window.__CSP_SUPPORT__ = cspSupport;
        
        // Report to analytics
        if (window.analytics) {
          window.analytics.track('CSP Support', cspSupport);
        }
      })();
    `;
  }
  
  formatPolicy(policy) {
    return Object.entries(policy)
      .filter(([_, values]) => values.length > 0)
      .map(([directive, sources]) => 
        directive === 'upgrade-insecure-requests' 
          ? directive 
          : `${directive} ${sources.join(' ')}`
      )
      .join('; ');
  }
}