Third-Party Resource Blocking

Third-Party Resource Blocking

Third-party resources frequently cause CSP violations, especially when applications depend on CDNs, analytics services, or external APIs:

// Common Error: External resources blocked
// Console: Refused to load the script 'https://cdn.example.com/library.js' because 
// it violates the following Content Security Policy directive: "script-src 'self'"

// PROBLEM: Missing external sources in CSP
// Original restrictive policy
Content-Security-Policy: default-src 'self'; script-src 'self';

// SOLUTION 1: Add specific trusted sources
Content-Security-Policy: 
  default-src 'self';
  script-src 'self' https://cdn.example.com https://apis.google.com;
  style-src 'self' https://fonts.googleapis.com;
  font-src 'self' https://fonts.gstatic.com;

// SOLUTION 2: Implement dynamic CSP based on features
class DynamicCSPManager {
  constructor() {
    this.basePolicy = {
      'default-src': ["'self'"],
      'script-src': ["'self'"],
      'style-src': ["'self'"],
      'img-src': ["'self'", 'data:'],
      'font-src': ["'self'"],
      'connect-src': ["'self'"]
    };
    
    this.features = {
      googleAnalytics: {
        'script-src': ['https://www.google-analytics.com'],
        'img-src': ['https://www.google-analytics.com'],
        'connect-src': ['https://www.google-analytics.com']
      },
      stripe: {
        'script-src': ['https://js.stripe.com'],
        'frame-src': ['https://js.stripe.com', 'https://checkout.stripe.com'],
        'connect-src': ['https://api.stripe.com']
      },
      youtube: {
        'frame-src': ['https://www.youtube.com', 'https://www.youtube-nocookie.com']
      }
    };
  }
  
  generatePolicy(enabledFeatures = []) {
    const policy = JSON.parse(JSON.stringify(this.basePolicy));
    
    // Add sources for enabled features
    enabledFeatures.forEach(feature => {
      if (this.features[feature]) {
        Object.entries(this.features[feature]).forEach(([directive, sources]) => {
          if (!policy[directive]) {
            policy[directive] = ["'self'"];
          }
          policy[directive].push(...sources);
        });
      }
    });
    
    return this.formatPolicy(policy);
  }
  
  formatPolicy(policy) {
    return Object.entries(policy)
      .map(([directive, sources]) => 
        `${directive} ${[...new Set(sources)].join(' ')}`
      )
      .join('; ');
  }
}

// Usage:
const cspManager = new DynamicCSPManager();
const policy = cspManager.generatePolicy(['googleAnalytics', 'stripe']);