Assessing Legacy Application Challenges

Assessing Legacy Application Challenges

Legacy applications often contain years or decades of accumulated code that predates modern security practices. Understanding these specific challenges is crucial for planning a successful CSP migration that doesn't break critical functionality.

Comprehensive legacy assessment framework:

// Legacy Application CSP Assessment Tool
class LegacyCSPAssessment {
  constructor(applicationUrl) {
    this.url = applicationUrl;
    this.findings = {
      inlineScripts: [],
      inlineStyles: [],
      eventHandlers: [],
      dynamicContent: [],
      thirdPartyDependencies: [],
      evalUsage: [],
      deprecatedPatterns: []
    };
  }
  
  async performComprehensiveAudit() {
    console.log('Starting legacy application CSP assessment...');
    
    const audit = {
      codeAnalysis: await this.analyzeCodebase(),
      runtimeAnalysis: await this.analyzeRuntime(),
      dependencyAnalysis: await this.analyzeDependencies(),
      securityRiskAssessment: await this.assessSecurityRisks(),
      migrationComplexity: await this.calculateMigrationComplexity()
    };
    
    return this.generateAssessmentReport(audit);
  }
  
  async analyzeCodebase() {
    const analysis = {
      totalFiles: 0,
      problematicPatterns: {},
      refactoringNeeded: []
    };
    
    // Scan for inline event handlers
    const eventHandlerPattern = /on(click|load|mouseover|change|submit|keyup|keydown|focus|blur)\s*=/gi;
    
    // Scan for eval usage
    const evalPattern = /eval\s*\(|new\s+Function\s*\(|setTimeout\s*\(['"]/gi;
    
    // Scan for document.write
    const documentWritePattern = /document\.(write|writeln)\s*\(/gi;
    
    // Scan for inline styles
    const inlineStylePattern = /style\s*=\s*["'][^"']+["']/gi;
    
    return {
      inlineHandlers: {
        count: 0,
        examples: [],
        estimatedEffort: 'hours'
      },
      evalUsage: {
        count: 0,
        contexts: [],
        alternatives: []
      },
      dynamicContent: {
        documentWrite: 0,
        innerHTML: 0,
        recommendations: []
      }
    };
  }
  
  async analyzeRuntime() {
    // Runtime analysis using headless browser
    const puppeteer = require('puppeteer');
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    
    // Intercept and analyze resources
    const resources = {
      scripts: new Map(),
      styles: new Map(),
      connections: new Set()
    };
    
    page.on('request', request => {
      const type = request.resourceType();
      const url = request.url();
      
      if (type === 'script') {
        resources.scripts.set(url, {
          type: 'external',
          origin: new URL(url).origin
        });
      } else if (type === 'stylesheet') {
        resources.styles.set(url, {
          type: 'external',
          origin: new URL(url).origin
        });
      } else if (type === 'xhr' || type === 'fetch') {
        resources.connections.add(new URL(url).origin);
      }
    });
    
    // Navigate and analyze
    await page.goto(this.url, { waitUntil: 'networkidle2' });
    
    // Analyze inline content
    const inlineAnalysis = await page.evaluate(() => {
      const results = {
        inlineScripts: [],
        inlineStyles: [],
        eventHandlers: []
      };
      
      // Find inline scripts
      document.querySelectorAll('script:not([src])').forEach(script => {
        results.inlineScripts.push({
          content: script.textContent.substring(0, 100) + '...',
          length: script.textContent.length,
          location: script.closest('[id]')?.id || 'unknown'
        });
      });
      
      // Find inline styles
      document.querySelectorAll('[style]').forEach(element => {
        results.inlineStyles.push({
          tag: element.tagName,
          style: element.getAttribute('style'),
          id: element.id || element.className
        });
      });
      
      // Find inline event handlers
      const eventAttributes = ['onclick', 'onload', 'onchange', 'onsubmit'];
      eventAttributes.forEach(attr => {
        document.querySelectorAll(`[${attr}]`).forEach(element => {
          results.eventHandlers.push({
            event: attr,
            handler: element.getAttribute(attr).substring(0, 50) + '...',
            element: element.tagName,
            id: element.id
          });
        });
      });
      
      return results;
    });
    
    await browser.close();
    
    return {
      resources,
      inlineContent: inlineAnalysis,
      recommendations: this.generateRuntimeRecommendations(resources, inlineAnalysis)
    };
  }
  
  generateAssessmentReport(audit) {
    const report = {
      summary: {
        applicationUrl: this.url,
        assessmentDate: new Date().toISOString(),
        overallReadiness: this.calculateReadinessScore(audit),
        estimatedEffort: this.estimateEffort(audit)
      },
      
      findings: {
        criticalIssues: this.identifyCriticalIssues(audit),
        moderateIssues: this.identifyModerateIssues(audit),
        minorIssues: this.identifyMinorIssues(audit)
      },
      
      migrationPlan: this.generateMigrationPlan(audit),
      
      recommendations: {
        immediate: [
          'Implement CSP in report-only mode',
          'Set up violation monitoring',
          'Create refactoring backlog'
        ],
        shortTerm: [
          'Refactor inline event handlers',
          'Move inline scripts to external files',
          'Implement nonce generation system'
        ],
        longTerm: [
          'Modernize JavaScript patterns',
          'Implement build-time CSP generation',
          'Automate CSP testing'
        ]
      }
    };
    
    return report;
  }
}