/** * Risk Signature Manager * Predefined risk signatures for threat detection * CWE-778 Compliance: Logs all signature matches and management operations */ const logger = require('./logger'); const logAggregator = require('./logAggregator'); const { db } = require('../database/db'); class RiskSignatureManager { constructor() { this.signatures = new Map(); this.initialize(); } /** * Initialize risk signature manager */ async initialize() { await this.createSignaturesTable(); await this.loadSignatures(); logger.info('[RiskSignatureManager] Initialized with predefined risk signatures'); // Log initialization (CWE-778) logAggregator.aggregate('risk_signature_manager', 'info', 'security', 'Risk signature manager initialized', { totalSignatures: this.signatures.size }); } /** * Create risk signatures table */ async createSignaturesTable() { return new Promise((resolve, reject) => { db.run(` CREATE TABLE IF NOT EXISTS risk_signatures ( id INTEGER PRIMARY KEY AUTOINCREMENT, signature_id TEXT UNIQUE NOT NULL, name TEXT NOT NULL, description TEXT, signature_type TEXT NOT NULL, pattern TEXT NOT NULL, match_type TEXT NOT NULL, threat_level TEXT NOT NULL, confidence REAL DEFAULT 0.8, enabled INTEGER DEFAULT 1, auto_block INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `, async (err) => { if (err) reject(err); else { db.run(`CREATE INDEX IF NOT EXISTS idx_signatures_type ON risk_signatures(signature_type, enabled)`); db.run(`CREATE INDEX IF NOT EXISTS idx_signatures_threat ON risk_signatures(threat_level, enabled)`); await this.createDefaultSignatures(); resolve(); } }); }); } /** * Create default risk signatures */ async createDefaultSignatures() { const defaultSignatures = [ // IP-based signatures { signature_id: 'SIG-IP-TOR', name: 'TOR Exit Node', description: 'Known TOR exit node IP address', signature_type: 'ip_address', pattern: '(^10\\.\\d+\\.\\d+\\.\\d+|^172\\.(1[6-9]|2[0-9]|3[01])\\.\\d+\\.\\d+|^192\\.168\\.\\d+\\.\\d+)', match_type: 'regex', threat_level: 'high', confidence: 0.9, auto_block: 0 }, { signature_id: 'SIG-IP-SUSPICIOUS', name: 'Suspicious IP Range', description: 'IP from suspicious geographic region', signature_type: 'ip_address', pattern: '', match_type: 'custom', threat_level: 'medium', confidence: 0.7, auto_block: 0 }, // User-agent signatures { signature_id: 'SIG-UA-BOT-MALICIOUS', name: 'Malicious Bot User-Agent', description: 'Known malicious bot signatures', signature_type: 'user_agent', pattern: '(scrapy|python-requests|curl|wget|nikto|sqlmap|havij|acunetix|nessus|openvas)', match_type: 'regex_case_insensitive', threat_level: 'high', confidence: 0.95, auto_block: 1 }, { signature_id: 'SIG-UA-VULNERABILITY-SCANNER', name: 'Vulnerability Scanner', description: 'Automated vulnerability scanning tools', signature_type: 'user_agent', pattern: '(nmap|masscan|zap|burp|metasploit|w3af|arachni)', match_type: 'regex_case_insensitive', threat_level: 'critical', confidence: 0.99, auto_block: 1 }, // Attack pattern signatures { signature_id: 'SIG-ATTACK-SQL-INJECTION', name: 'SQL Injection Pattern', description: 'Common SQL injection attack patterns', signature_type: 'attack_pattern', pattern: '(union.*select|select.*from|insert.*into|delete.*from|drop.*table|exec.*xp_|script.*alert)', match_type: 'regex_case_insensitive', threat_level: 'critical', confidence: 0.85, auto_block: 1 }, { signature_id: 'SIG-ATTACK-XSS', name: 'Cross-Site Scripting Pattern', description: 'XSS attack patterns', signature_type: 'attack_pattern', pattern: '( { db.run( `INSERT OR IGNORE INTO risk_signatures (signature_id, name, description, signature_type, pattern, match_type, threat_level, confidence, auto_block) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ signature.signature_id, signature.name, signature.description, signature.signature_type, signature.pattern, signature.match_type, signature.threat_level, signature.confidence, signature.auto_block ], (err) => { if (err) reject(err); else resolve(); } ); }); } logger.info(`[RiskSignatureManager] Created ${defaultSignatures.length} default signatures`); } /** * Load signatures from database into memory */ async loadSignatures() { return new Promise((resolve, reject) => { db.all( `SELECT * FROM risk_signatures WHERE enabled = 1`, [], (err, rows) => { if (err) { reject(err); } else { this.signatures.clear(); rows.forEach(row => { this.signatures.set(row.signature_id, row); }); logger.info(`[RiskSignatureManager] Loaded ${rows.length} active signatures`); resolve(); } } ); }); } /** * Match input against risk signatures * CWE-778: Logs all signature matches */ async matchSignatures(input, signatureType, context = {}) { const matchingSignatures = Array.from(this.signatures.values()).filter( s => s.signature_type === signatureType ); if (matchingSignatures.length === 0) { return { matched: false, signatures: [] }; } const matches = []; for (const signature of matchingSignatures) { const matched = this.testPattern(input, signature.pattern, signature.match_type); if (matched) { matches.push({ ...signature, matchedInput: input, context }); // Log signature match (CWE-778) logAggregator.aggregate('risk_signature_manager', 'warn', 'security', 'Risk signature matched', { signatureId: signature.signature_id, signatureName: signature.name, signatureType, threatLevel: signature.threat_level, confidence: signature.confidence, autoBlock: signature.auto_block === 1, matchedInput: input.substring(0, 100), // Truncate for logging context }); logger.warn(`[RiskSignatureManager] Signature matched: ${signature.name} (${signature.threat_level})`); } } return { matched: matches.length > 0, signatures: matches, highestThreat: matches.length > 0 ? this.getHighestThreatLevel(matches) : null, shouldAutoBlock: matches.some(m => m.auto_block === 1) }; } /** * Test pattern against input */ testPattern(input, pattern, matchType) { try { switch (matchType) { case 'regex': return new RegExp(pattern).test(input); case 'regex_case_insensitive': return new RegExp(pattern, 'i').test(input); case 'exact': return input === pattern; case 'contains': return input.includes(pattern); case 'custom': // Custom patterns handled by specific detection methods return false; default: return false; } } catch (error) { logger.error(`[RiskSignatureManager] Pattern test error: ${error.message}`); return false; } } /** * Get highest threat level from matches */ getHighestThreatLevel(matches) { const threatLevels = { critical: 4, high: 3, medium: 2, low: 1 }; let highest = 'low'; let highestScore = 0; for (const match of matches) { const score = threatLevels[match.threat_level] || 0; if (score > highestScore) { highestScore = score; highest = match.threat_level; } } return highest; } /** * Get all signatures */ async getSignatures(filters = {}) { const { signatureType, threatLevel, enabled, limit = 100 } = filters; let whereClause = []; let params = []; if (signatureType) { whereClause.push('signature_type = ?'); params.push(signatureType); } if (threatLevel) { whereClause.push('threat_level = ?'); params.push(threatLevel); } if (enabled !== undefined) { whereClause.push('enabled = ?'); params.push(enabled ? 1 : 0); } const where = whereClause.length > 0 ? `WHERE ${whereClause.join(' AND ')}` : ''; params.push(limit); return new Promise((resolve, reject) => { db.all( `SELECT * FROM risk_signatures ${where} ORDER BY threat_level DESC, confidence DESC LIMIT ?`, params, (err, rows) => { if (err) reject(err); else resolve(rows); } ); }); } /** * Get signature by ID */ async getSignatureById(signatureId) { return new Promise((resolve, reject) => { db.get( `SELECT * FROM risk_signatures WHERE signature_id = ?`, [signatureId], (err, row) => { if (err) reject(err); else resolve(row); } ); }); } /** * Create new signature * CWE-778: Logs signature creation */ async createSignature(data, userId) { const signatureId = `SIG-${Date.now()}-${Math.random().toString(36).substr(2, 9).toUpperCase()}`; return new Promise((resolve, reject) => { db.run( `INSERT INTO risk_signatures (signature_id, name, description, signature_type, pattern, match_type, threat_level, confidence, enabled, auto_block) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ signatureId, data.name, data.description || '', data.signature_type, data.pattern, data.match_type, data.threat_level, data.confidence || 0.8, data.enabled !== undefined ? (data.enabled ? 1 : 0) : 1, data.auto_block !== undefined ? (data.auto_block ? 1 : 0) : 0 ], async (err) => { if (err) { reject(err); } else { await this.loadSignatures(); // Log signature creation (CWE-778) logAggregator.aggregate('risk_signature_manager', 'info', 'security', 'Risk signature created', { signatureId, userId, name: data.name, signatureType: data.signature_type, threatLevel: data.threat_level, autoBlock: data.auto_block === 1 }); logger.info(`[RiskSignatureManager] Signature created: ${signatureId} by user ${userId}`); resolve({ signatureId }); } } ); }); } /** * Update signature * CWE-778: Logs signature modifications */ async updateSignature(signatureId, updates, userId) { const allowedFields = ['name', 'description', 'pattern', 'match_type', 'threat_level', 'confidence', 'enabled', 'auto_block']; const setClause = []; const params = []; for (const [key, value] of Object.entries(updates)) { if (allowedFields.includes(key)) { setClause.push(`${key} = ?`); params.push((key === 'enabled' || key === 'auto_block') ? (value ? 1 : 0) : value); } } if (setClause.length === 0) { throw new Error('No valid fields to update'); } setClause.push('updated_at = CURRENT_TIMESTAMP'); params.push(signatureId); return new Promise((resolve, reject) => { db.run( `UPDATE risk_signatures SET ${setClause.join(', ')} WHERE signature_id = ?`, params, async (err) => { if (err) { reject(err); } else { await this.loadSignatures(); // Log signature update (CWE-778) logAggregator.aggregate('risk_signature_manager', 'info', 'security', 'Risk signature updated', { signatureId, userId, updates }); logger.info(`[RiskSignatureManager] Signature updated: ${signatureId} by user ${userId}`); resolve({ success: true }); } } ); }); } /** * Delete signature * CWE-778: Logs signature deletion */ async deleteSignature(signatureId, userId) { return new Promise((resolve, reject) => { db.run( `DELETE FROM risk_signatures WHERE signature_id = ?`, [signatureId], async (err) => { if (err) { reject(err); } else { await this.loadSignatures(); // Log signature deletion (CWE-778) logAggregator.aggregate('risk_signature_manager', 'warn', 'security', 'Risk signature deleted', { signatureId, userId }); logger.info(`[RiskSignatureManager] Signature deleted: ${signatureId} by user ${userId}`); resolve({ success: true }); } } ); }); } /** * Get signature statistics */ async getStatistics() { return new Promise((resolve, reject) => { db.get( `SELECT COUNT(*) as total, SUM(CASE WHEN enabled = 1 THEN 1 ELSE 0 END) as enabled, SUM(CASE WHEN enabled = 0 THEN 1 ELSE 0 END) as disabled, SUM(CASE WHEN auto_block = 1 THEN 1 ELSE 0 END) as auto_block_enabled, COUNT(DISTINCT signature_type) as unique_types, COUNT(DISTINCT threat_level) as unique_threat_levels FROM risk_signatures`, [], (err, row) => { if (err) reject(err); else resolve(row); } ); }); } } // Create singleton instance const riskSignatureManager = new RiskSignatureManager(); module.exports = riskSignatureManager;