UNPKG

@ordojs/security

Version:

Security package for OrdoJS with XSS, CSRF, and injection protection

265 lines (232 loc) 7.66 kB
/** * XSS vulnerability detection and analysis */ /** * Types of XSS vulnerabilities */ export enum XssVulnerabilityType { REFLECTED = 'reflected', STORED = 'stored', DOM_BASED = 'dom-based', TEMPLATE_INJECTION = 'template-injection', } /** * Severity levels for vulnerabilities */ export enum VulnerabilitySeverity { LOW = 'low', MEDIUM = 'medium', HIGH = 'high', CRITICAL = 'critical', } /** * XSS vulnerability detection result */ export interface XssVulnerability { type: XssVulnerabilityType; severity: VulnerabilitySeverity; description: string; location: string; payload: string; recommendation: string; } /** * Common XSS attack patterns */ const XSS_PATTERNS = [ // Script tags /<script[^>]*>.*?<\/script>/gi, /<script[^>]*>/gi, // Event handlers /on\w+\s*=\s*['"]/gi, // JavaScript URLs /javascript\s*:/gi, // Data URLs with JavaScript /data\s*:\s*text\/html/gi, // SVG with script /<svg[^>]*>.*?<\/svg>/gi, // Object/embed tags /<(object|embed|applet)[^>]*>/gi, // Meta refresh /<meta[^>]*http-equiv\s*=\s*['"]\s*refresh/gi, // Link with JavaScript /<link[^>]*href\s*=\s*['"]\s*javascript/gi, // Style with expression /expression\s*\(/gi, // Import statements /@import/gi, ]; /** * Dangerous HTML attributes that can execute JavaScript */ const DANGEROUS_ATTRIBUTES = [ 'onabort', 'onblur', 'onchange', 'onclick', 'ondblclick', 'onerror', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset', 'onresize', 'onselect', 'onsubmit', 'onunload', 'onafterprint', 'onbeforeprint', 'onbeforeunload', 'onhashchange', 'onmessage', 'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpopstate', 'onstorage', 'oncontextmenu', 'oninput', 'oninvalid', 'onsearch', ]; /** * XSS vulnerability detector */ export class XssVulnerabilityDetector { private patterns: RegExp[]; private dangerousAttributes: string[]; /** * Create a new XSS vulnerability detector */ constructor() { this.patterns = [...XSS_PATTERNS]; this.dangerousAttributes = [...DANGEROUS_ATTRIBUTES]; } /** * Scan content for potential XSS vulnerabilities * @param content Content to scan * @param location Location identifier for the content * @returns Array of detected vulnerabilities */ scanContent(content: string, location: string = 'unknown'): XssVulnerability[] { const vulnerabilities: XssVulnerability[] = []; // Check for script injection patterns for (const pattern of this.patterns) { const matches = content.match(pattern); if (matches) { for (const match of matches) { vulnerabilities.push({ type: this.determineVulnerabilityType(match), severity: this.determineSeverity(match), description: `Potential XSS vulnerability detected: ${match.substring(0, 100)}...`, location, payload: match, recommendation: this.getRecommendation(match), }); } } } // Check for dangerous attributes for (const attr of this.dangerousAttributes) { const attrPattern = new RegExp(`${attr}\\s*=`, 'gi'); if (attrPattern.test(content)) { vulnerabilities.push({ type: XssVulnerabilityType.DOM_BASED, severity: VulnerabilitySeverity.HIGH, description: `Dangerous event handler attribute detected: ${attr}`, location, payload: attr, recommendation: 'Remove event handler attributes and use proper event listeners instead.', }); } } return vulnerabilities; } /** * Check if a string contains potential XSS payload * @param input Input string to check * @returns True if potential XSS is detected */ containsXss(input: string): boolean { return this.patterns.some(pattern => pattern.test(input)) || this.dangerousAttributes.some(attr => new RegExp(`${attr}\\s*=`, 'gi').test(input) ); } /** * Analyze template for potential injection vulnerabilities * @param template Template string * @param variables Variables used in template * @returns Array of vulnerabilities */ analyzeTemplate(template: string, variables: Record<string, unknown> = {}): XssVulnerability[] { const vulnerabilities: XssVulnerability[] = []; // Check for unescaped variable interpolation const interpolationPattern = /\$\{([^}]+)\}/g; let match; while ((match = interpolationPattern.exec(template)) !== null) { const variableName = match[1]?.trim(); if (!variableName) continue; const variableValue = variables[variableName]; if (typeof variableValue === 'string' && this.containsXss(variableValue)) { vulnerabilities.push({ type: XssVulnerabilityType.TEMPLATE_INJECTION, severity: VulnerabilitySeverity.CRITICAL, description: `Unescaped variable interpolation with potential XSS: \${${variableName}}`, location: 'template', payload: String(variableValue), recommendation: 'Use proper HTML escaping for all template variables.', }); } } return vulnerabilities; } /** * Determine the type of XSS vulnerability based on the payload * @param payload The detected payload * @returns Vulnerability type */ private determineVulnerabilityType(payload: string): XssVulnerabilityType { if (payload.includes('<script')) { return XssVulnerabilityType.REFLECTED; } if (payload.includes('javascript:')) { return XssVulnerabilityType.DOM_BASED; } if (payload.includes('${') || payload.includes('{{')) { return XssVulnerabilityType.TEMPLATE_INJECTION; } return XssVulnerabilityType.STORED; } /** * Determine the severity of a vulnerability based on the payload * @param payload The detected payload * @returns Vulnerability severity */ private determineSeverity(payload: string): VulnerabilitySeverity { if (payload.includes('<script') || payload.includes('javascript:')) { return VulnerabilitySeverity.CRITICAL; } if (payload.includes('on') && payload.includes('=')) { return VulnerabilitySeverity.HIGH; } if (payload.includes('<') || payload.includes('>')) { return VulnerabilitySeverity.MEDIUM; } return VulnerabilitySeverity.LOW; } /** * Get recommendation for fixing a vulnerability * @param payload The detected payload * @returns Recommendation string */ private getRecommendation(payload: string): string { if (payload.includes('<script')) { return 'Remove script tags and use proper JavaScript loading mechanisms.'; } if (payload.includes('javascript:')) { return 'Replace javascript: URLs with proper event handlers.'; } if (payload.includes('on') && payload.includes('=')) { return 'Remove inline event handlers and use addEventListener instead.'; } return 'Sanitize or escape the content before rendering.'; } /** * Add a custom XSS pattern to detect * @param pattern Regular expression pattern */ addPattern(pattern: RegExp): void { this.patterns.push(pattern); } /** * Add a custom dangerous attribute to detect * @param attribute Attribute name */ addDangerousAttribute(attribute: string): void { this.dangerousAttributes.push(attribute.toLowerCase()); } } /** * Default XSS vulnerability detector instance */ export const defaultXssDetector = new XssVulnerabilityDetector();