Phased Migration Strategy

Phased Migration Strategy

Migrating legacy applications requires a carefully phased approach that minimizes risk while progressively improving security:

// Phased CSP Migration Manager
class PhasedCSPMigration {
  constructor(application) {
    this.application = application;
    this.currentPhase = 0;
    this.phases = this.defineMigrationPhases();
  }
  
  defineMigrationPhases() {
    return [
      {
        name: 'Phase 0: Preparation',
        duration: '2-4 weeks',
        objectives: [
          'Complete application assessment',
          'Set up monitoring infrastructure',
          'Train development team',
          'Create rollback procedures'
        ],
        implementation: this.implementPhase0(),
        successCriteria: {
          monitoringSetup: true,
          teamTraining: 100,
          rollbackTested: true
        }
      },
      {
        name: 'Phase 1: Report-Only Deployment',
        duration: '4-6 weeks',
        objectives: [
          'Deploy permissive report-only policy',
          'Collect comprehensive violation data',
          'Identify all resource dependencies',
          'Build initial allowlist'
        ],
        implementation: this.implementPhase1(),
        successCriteria: {
          coverageDays: 30,
          violationsAnalyzed: true,
          falsePositivesResolved: 95
        }
      },
      {
        name: 'Phase 2: Code Refactoring',
        duration: '8-12 weeks',
        objectives: [
          'Refactor inline event handlers',
          'Externalize inline scripts',
          'Implement nonce system',
          'Update third-party integrations'
        ],
        implementation: this.implementPhase2(),
        successCriteria: {
          inlineHandlersRemoved: 100,
          inlineScriptsReduced: 90,
          nonceSystemOperational: true
        }
      },
      {
        name: 'Phase 3: Gradual Enforcement',
        duration: '4-6 weeks',
        objectives: [
          'Enable enforcement for subset of users',
          'Monitor for functionality issues',
          'Refine policy based on feedback',
          'Expand enforcement gradually'
        ],
        implementation: this.implementPhase3(),
        successCriteria: {
          enforcementPercentage: 100,
          userImpactAcceptable: true,
          performanceImpactMinimal: true
        }
      },
      {
        name: 'Phase 4: Optimization',
        duration: 'Ongoing',
        objectives: [
          'Tighten security policies',
          'Optimize performance',
          'Automate policy management',
          'Establish maintenance procedures'
        ],
        implementation: this.implementPhase4(),
        successCriteria: {
          securityPostureImproved: true,
          automationImplemented: true,
          maintenanceProcessEstablished: true
        }
      }
    ];
  }
  
  implementPhase0() {
    return {
      monitoring: `
        // Set up comprehensive CSP monitoring
        class CSPMonitoringSetup {
          constructor() {
            this.endpoints = {
              reportUri: '/api/csp-reports',
              analytics: '/api/csp-analytics',
              alerts: '/api/csp-alerts'
            };
          }
          
          setupReportingEndpoint() {
            app.post(this.endpoints.reportUri, (req, res) => {
              const report = req.body['csp-report'];
              
              // Store in database
              db.cspReports.insert({
                timestamp: new Date(),
                violation: report,
                userAgent: req.headers['user-agent'],
                sessionId: req.session?.id
              });
              
              // Real-time analysis
              this.analyzeViolation(report);
              
              res.status(204).end();
            });
          }
          
          setupDashboard() {
            return {
              metrics: [
                'Total violations per hour',
                'Unique violation sources',
                'Violation by directive',
                'User impact assessment'
              ],
              alerts: [
                'Spike in violations',
                'New violation source',
                'Critical functionality blocked'
              ]
            };
          }
        }
      `,
      
      training: {
        developers: [
          'CSP fundamentals workshop',
          'Legacy code refactoring techniques',
          'CSP debugging tools training'
        ],
        qa: [
          'CSP testing procedures',
          'Violation identification',
          'Regression testing with CSP'
        ],
        support: [
          'Common CSP issues',
          'User complaint handling',
          'Escalation procedures'
        ]
      }
    };
  }
  
  implementPhase1() {
    return {
      initialPolicy: `
        // Permissive report-only policy for discovery
        Content-Security-Policy-Report-Only: 
          default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;
          report-uri /api/csp-reports;
      `,
      
      violationAnalyzer: `
        class ViolationAnalyzer {
          constructor() {
            this.violations = new Map();
            this.patterns = new Map();
          }
          
          analyzeViolations(reports) {
            const analysis = {
              byDirective: {},
              bySource: {},
              byPage: {},
              recommendations: []
            };
            
            reports.forEach(report => {
              const violation = report['csp-report'];
              const directive = violation['violated-directive'];
              const source = violation['blocked-uri'];
              
              // Group by directive
              if (!analysis.byDirective[directive]) {
                analysis.byDirective[directive] = {
                  count: 0,
                  sources: new Set()
                };
              }
              analysis.byDirective[directive].count++;
              analysis.byDirective[directive].sources.add(source);
              
              // Identify patterns
              if (source.includes('google-analytics')) {
                analysis.recommendations.push({
                  action: 'Add Google Analytics to CSP',
                  directives: ['script-src', 'img-src', 'connect-src'],
                  sources: ['https://www.google-analytics.com']
                });
              }
            });
            
            return analysis;
          }
        }
      `
    };
  }
  
  implementPhase2() {
    return {
      refactoringTools: `
        // Automated refactoring helpers
        class LegacyCodeRefactorer {
          refactorInlineHandlers(html) {
            const $ = cheerio.load(html);
            const handlers = [];
            
            // Extract and remove inline handlers
            $('[onclick], [onload], [onchange]').each((i, elem) => {
              const $elem = $(elem);
              const events = {};
              
              ['onclick', 'onload', 'onchange'].forEach(attr => {
                if ($elem.attr(attr)) {
                  events[attr] = $elem.attr(attr);
                  $elem.removeAttr(attr);
                }
              });
              
              if (Object.keys(events).length > 0) {
                const id = $elem.attr('id') || \`legacy-elem-\${i}\`;
                $elem.attr('id', id);
                
                handlers.push({ id, events });
              }
            });
            
            // Generate external script
            const script = this.generateEventScript(handlers);
            
            return {
              html: $.html(),
              script: script
            };
          }
          
          generateEventScript(handlers) {
            let script = 'document.addEventListener("DOMContentLoaded", function() {\\n';
            
            handlers.forEach(({ id, events }) => {
              Object.entries(events).forEach(([event, handler]) => {
                const eventType = event.substring(2); // Remove 'on' prefix
                script += \`  document.getElementById('\${id}').addEventListener('\${eventType}', function(event) {\\n\`;
                script += \`    \${handler}\\n\`;
                script += \`  });\\n\`;
              });
            });
            
            script += '});';
            return script;
          }
        }
      `,
      
      nonceImplementation: `
        // Nonce system for legacy applications
        class LegacyNonceSystem {
          constructor() {
            this.nonceCache = new Map();
          }
          
          middleware() {
            return (req, res, next) => {
              const nonce = crypto.randomBytes(16).toString('base64');
              res.locals.nonce = nonce;
              
              // Override render for legacy templating engines
              this.overrideRender(res, nonce);
              
              // Set CSP header with nonce
              const policy = this.generateNoncePolicy(nonce);
              res.setHeader('Content-Security-Policy-Report-Only', policy);
              
              next();
            };
          }
          
          overrideRender(res, nonce) {
            const originalRender = res.render;
            
            res.render = function(view, options, callback) {
              options = options || {};
              options.cspNonce = nonce;
              
              // Add nonce injection helper
              options.injectNonce = (html) => {
                return html
                  .replace(/<script(?![^>]*nonce)/gi, \`<script nonce="\${nonce}"\`)
                  .replace(/<style(?![^>]*nonce)/gi, \`<style nonce="\${nonce}"\`);
              };
              
              originalRender.call(this, view, options, callback);
            };
          }
        }
      `
    };
  }
}