Security-First Development Practices

Security-First Development Practices

Integrating CSP considerations into the development workflow ensures security becomes part of the development process rather than an afterthought:

// CSP-Aware Development Framework
class CSPDevelopmentFramework {
  constructor() {
    this.guidelines = this.createDevelopmentGuidelines();
    this.tools = this.setupDevelopmentTools();
  }
  
  createDevelopmentGuidelines() {
    return {
      scriptHandling: {
        preferred: [
          'External script files with SRI',
          'Event listeners instead of inline handlers',
          'Modern frameworks with CSP support'
        ],
        avoid: [
          'Inline event handlers (onclick, onload)',
          'eval() and Function() constructor',
          'innerHTML for script content'
        ],
        migration: {
          // Instead of: <button onclick="doSomething()">
          from: `<button onclick="doSomething()">Click</button>`,
          to: `
            <button id="action-btn">Click</button>
            <script src="/js/handlers.js"></script>
          `,
          handler: `
            document.getElementById('action-btn')
              .addEventListener('click', doSomething);
          `
        }
      },
      
      styleHandling: {
        preferred: [
          'External stylesheets',
          'CSS classes over inline styles',
          'CSS-in-JS with nonce support'
        ],
        avoid: [
          'style attribute usage',
          'Dynamic style injection without nonces',
          'Unsafe CSS properties'
        ]
      },
      
      resourceLoading: {
        preferred: [
          'First-party hosting when possible',
          'Subresource Integrity for third-party resources',
          'Explicit resource declaration'
        ],
        implementation: this.createResourceLoader()
      }
    };
  }
  
  createResourceLoader() {
    return `
      class SecureResourceLoader {
        constructor(allowedOrigins) {
          this.allowedOrigins = new Set(allowedOrigins);
          this.loadedResources = new Map();
        }
        
        async loadScript(url, options = {}) {
          // Validate origin
          const origin = new URL(url).origin;
          if (!this.allowedOrigins.has(origin)) {
            throw new Error(\`Origin not allowed: \${origin}\`);
          }
          
          // Check if already loaded
          if (this.loadedResources.has(url)) {
            return this.loadedResources.get(url);
          }
          
          const script = document.createElement('script');
          script.src = url;
          
          // Add security attributes
          if (options.integrity) {
            script.integrity = options.integrity;
            script.crossOrigin = 'anonymous';
          }
          
          if (options.nonce) {
            script.nonce = options.nonce;
          }
          
          // Load script
          const promise = new Promise((resolve, reject) => {
            script.onload = resolve;
            script.onerror = reject;
          });
          
          document.head.appendChild(script);
          this.loadedResources.set(url, promise);
          
          return promise;
        }
      }
    `;
  }
  
  setupDevelopmentTools() {
    return {
      linters: this.createCSPLintRules(),
      buildTools: this.createWebpackPlugin(),
      testing: this.createTestingFramework()
    };
  }
  
  createCSPLintRules() {
    return {
      rules: {
        'no-inline-handlers': {
          message: 'Inline event handlers violate CSP',
          severity: 'error',
          fix: 'Use addEventListener instead'
        },
        'no-eval': {
          message: 'eval() is blocked by CSP',
          severity: 'error',
          fix: 'Use JSON.parse() or other safe alternatives'
        },
        'no-inline-styles': {
          message: 'Inline styles should be avoided',
          severity: 'warning',
          fix: 'Use CSS classes or nonce-protected styles'
        }
      }
    };
  }
}