/** * Security Audit Logger * Tracks security-related events for compliance and forensics * Integrated with SIEM for centralized log aggregation */ const logger = require('./logger'); const { db } = require('../database/db'); const logAggregator = require('./logAggregator'); class SecurityAuditLogger { /** * Log authentication events */ static async logAuthEvent(eventType, userId, details = {}) { const event = { event_type: eventType, user_id: userId, ip_address: details.ip || 'unknown', user_agent: details.userAgent || 'unknown', success: details.success !== false, failure_reason: details.failureReason || null, metadata: JSON.stringify(details.metadata || {}), timestamp: new Date().toISOString() }; try { await new Promise((resolve, reject) => { db.run( `INSERT INTO security_audit_log (event_type, user_id, ip_address, user_agent, success, failure_reason, metadata, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [event.event_type, event.user_id, event.ip_address, event.user_agent, event.success ? 1 : 0, event.failure_reason, event.metadata, event.timestamp], (err) => err ? reject(err) : resolve() ); }); logger.info(`[SECURITY] ${eventType}: user=${userId}, ip=${event.ip_address}, success=${event.success}`); // Aggregate to SIEM const level = event.success ? 'info' : 'warn'; const source = eventType.startsWith('LOGIN') || eventType.includes('PASSWORD') ? 'authentication' : 'security_audit'; logAggregator.aggregate(source, level, 'authentication', `${eventType}: ${event.success ? 'success' : 'failure'}`, { userId: event.user_id, ip: event.ip_address, userAgent: event.user_agent, failureReason: event.failure_reason, metadata: details.metadata || {} }); } catch (error) { logger.error('Failed to log security event:', error); } } /** * Log login attempt */ static async logLoginAttempt(username, success, details = {}) { return this.logAuthEvent('LOGIN_ATTEMPT', null, { success, failureReason: success ? null : (details.reason || 'Invalid credentials'), ip: details.ip, userAgent: details.userAgent, metadata: { username } }); } /** * Log successful login */ static async logLoginSuccess(userId, details = {}) { return this.logAuthEvent('LOGIN_SUCCESS', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { twoFactorUsed: details.twoFactorUsed || false } }); } /** * Log failed login */ static async logLoginFailure(username, reason, details = {}) { return this.logAuthEvent('LOGIN_FAILURE', null, { success: false, failureReason: reason, ip: details.ip, userAgent: details.userAgent, metadata: { username } }); } /** * Log account lockout */ static async logAccountLockout(userId, details = {}) { return this.logAuthEvent('ACCOUNT_LOCKOUT', userId, { success: false, failureReason: 'Too many failed login attempts', ip: details.ip, userAgent: details.userAgent, metadata: { failedAttempts: details.failedAttempts } }); } /** * Log password change */ static async logPasswordChange(userId, details = {}) { return this.logAuthEvent('PASSWORD_CHANGE', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { forced: details.forced || false, expired: details.expired || false } }); } /** * Log 2FA events */ static async log2FAEvent(eventType, userId, success, details = {}) { return this.logAuthEvent(eventType, userId, { success, failureReason: success ? null : (details.reason || 'Invalid code'), ip: details.ip, userAgent: details.userAgent, metadata: details.metadata || {} }); } /** * Log session events */ static async logSessionEvent(eventType, userId, details = {}) { return this.logAuthEvent(eventType, userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { sessionId: details.sessionId } }); } /** * Log privilege escalation */ static async logPrivilegeEscalation(userId, details = {}) { return this.logAuthEvent('PRIVILEGE_ESCALATION', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { fromRole: details.fromRole, toRole: details.toRole, grantedBy: details.grantedBy } }); } /** * Get recent security events for a user */ static async getUserSecurityEvents(userId, limit = 50) { return new Promise((resolve, reject) => { db.all( `SELECT * FROM security_audit_log WHERE user_id = ? ORDER BY timestamp DESC LIMIT ?`, [userId, limit], (err, rows) => err ? reject(err) : resolve(rows) ); }); } /** * Get failed login attempts for an IP */ static async getFailedAttemptsForIP(ipAddress, timeWindowMinutes = 30) { const cutoffTime = new Date(Date.now() - timeWindowMinutes * 60 * 1000).toISOString(); return new Promise((resolve, reject) => { db.get( `SELECT COUNT(*) as count FROM security_audit_log WHERE event_type IN ('LOGIN_FAILURE', 'LOGIN_ATTEMPT') AND success = 0 AND ip_address = ? AND timestamp > ?`, [ipAddress, cutoffTime], (err, row) => err ? reject(err) : resolve(row.count || 0) ); }); } /** * Get failed login attempts for a user */ static async getFailedAttemptsForUser(username, timeWindowMinutes = 30) { const cutoffTime = new Date(Date.now() - timeWindowMinutes * 60 * 1000).toISOString(); return new Promise((resolve, reject) => { db.get( `SELECT COUNT(*) as count FROM security_audit_log WHERE event_type IN ('LOGIN_FAILURE', 'LOGIN_ATTEMPT') AND success = 0 AND metadata LIKE ? AND timestamp > ?`, [`%"username":"${username}"%`, cutoffTime], (err, row) => err ? reject(err) : resolve(row.count || 0) ); }); } /** * Clear old audit logs (data retention) */ static async cleanupOldLogs(retentionDays = 90) { const cutoffDate = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000).toISOString(); return new Promise((resolve, reject) => { db.run( 'DELETE FROM security_audit_log WHERE timestamp < ?', [cutoffDate], function(err) { if (err) reject(err); else { logger.info(`Cleaned up ${this.changes} old security audit logs`); resolve(this.changes); } } ); }); } /** * CWE-778: Log token issuance (JWT, OAuth, etc.) * Includes relevant metadata such as client ID, IP address, device info */ static async logTokenIssuance(userId, tokenType, details = {}) { return this.logAuthEvent('TOKEN_ISSUED', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { tokenType: tokenType, // 'JWT', 'REFRESH', 'TEMP_2FA', 'OAUTH' clientId: details.clientId, deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent), expiresIn: details.expiresIn, purpose: details.purpose, // 'login', '2fa', 'registration', 'password_reset' scope: details.scope, grantType: details.grantType } }); } /** * CWE-778: Log token refresh */ static async logTokenRefresh(userId, details = {}) { return this.logAuthEvent('TOKEN_REFRESHED', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { tokenType: details.tokenType || 'JWT', clientId: details.clientId, deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent), oldTokenExpiry: details.oldTokenExpiry, newTokenExpiry: details.newTokenExpiry } }); } /** * CWE-778: Log token revocation */ static async logTokenRevocation(userId, reason, details = {}) { return this.logAuthEvent('TOKEN_REVOKED', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { reason: reason, // 'logout', 'password_change', 'security_breach', 'admin_action' tokenType: details.tokenType || 'JWT', sessionId: details.sessionId, revokedBy: details.revokedBy // user_id of admin who revoked it } }); } /** * CWE-778: Log privilege changes * Any activities where user's privilege level changes */ static async logPrivilegeChange(userId, action, details = {}) { return this.logAuthEvent('PRIVILEGE_CHANGE', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { action: action, // 'role_assigned', 'role_removed', 'permission_granted', 'permission_revoked' previousRole: details.previousRole, newRole: details.newRole, previousPermissions: details.previousPermissions, newPermissions: details.newPermissions, changedBy: details.changedBy, // user_id of admin who made the change changedByUsername: details.changedByUsername, reason: details.reason, affectedUser: details.affectedUser // username of the user being changed } }); } /** * CWE-778: Log permission grant */ static async logPermissionGrant(userId, permission, details = {}) { return this.logAuthEvent('PERMISSION_GRANTED', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { permission: permission, grantedBy: details.grantedBy, grantedByUsername: details.grantedByUsername, scope: details.scope, expiresAt: details.expiresAt } }); } /** * CWE-778: Log permission revocation */ static async logPermissionRevocation(userId, permission, details = {}) { return this.logAuthEvent('PERMISSION_REVOKED', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { permission: permission, revokedBy: details.revokedBy, revokedByUsername: details.revokedByUsername, reason: details.reason } }); } /** * CWE-778: Log user activation/deactivation */ static async logAccountStatusChange(userId, newStatus, details = {}) { return this.logAuthEvent('ACCOUNT_STATUS_CHANGED', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { previousStatus: details.previousStatus, newStatus: newStatus, // 'active', 'inactive', 'suspended', 'locked' changedBy: details.changedBy, changedByUsername: details.changedByUsername, reason: details.reason } }); } /** * CWE-778: Log administrative activities * For admin actions like user creation, deletion, unlock, force logout */ static async logAdminActivity(adminId, action, details = {}) { return this.logAuthEvent('ADMIN_ACTIVITY', adminId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { action: action, // 'user_created', 'user_deleted', 'account_unlocked', 'password_reset', 'force_logout' targetUserId: details.targetUserId, targetUsername: details.targetUsername, adminUsername: details.adminUsername, changes: details.changes, reason: details.reason, deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent) } }); } /** * CWE-778: Log sensitive data access * For accessing user lists, settings, VPN configs, backups, etc. */ static async logSensitiveDataAccess(userId, dataType, details = {}) { return this.logAuthEvent('SENSITIVE_DATA_ACCESS', userId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { dataType: dataType, // 'user_list', 'user_details', 'settings', 'vpn_configs', 'backups', 'audit_logs' accessMethod: details.accessMethod || 'view', // 'view', 'export', 'download' recordCount: details.recordCount, filters: details.filters, scope: details.scope, // 'own', 'all', 'specific' deviceInfo: details.deviceInfo || this.extractDeviceInfo(details.userAgent) } }); } /** * Extract device info from user agent */ static extractDeviceInfo(userAgent = '') { if (!userAgent) return { deviceType: 'unknown', os: 'unknown', browser: 'unknown' }; const ua = userAgent.toLowerCase(); // Device type let deviceType = 'desktop'; if (/bot|crawler|spider/.test(ua)) deviceType = 'bot'; else if (/mobile|android|iphone|ipod/.test(ua)) deviceType = 'mobile'; else if (/tablet|ipad/.test(ua)) deviceType = 'tablet'; // Operating System let os = 'unknown'; if (/windows/.test(ua)) os = 'Windows'; else if (/mac os|macos/.test(ua)) os = 'macOS'; else if (/linux/.test(ua)) os = 'Linux'; else if (/android/.test(ua)) os = 'Android'; else if (/ios|iphone|ipad/.test(ua)) os = 'iOS'; // Browser let browser = 'unknown'; if (/firefox/.test(ua)) browser = 'Firefox'; else if (/chrome/.test(ua) && !/edge|edg/.test(ua)) browser = 'Chrome'; else if (/safari/.test(ua) && !/chrome/.test(ua)) browser = 'Safari'; else if (/edge|edg/.test(ua)) browser = 'Edge'; else if (/opera|opr/.test(ua)) browser = 'Opera'; return { deviceType, os, browser }; } /** * Get comprehensive audit statistics */ static async getAuditStatistics(timeRangeDays = 30) { const cutoffDate = new Date(Date.now() - timeRangeDays * 24 * 60 * 60 * 1000).toISOString(); return new Promise((resolve, reject) => { db.all( `SELECT event_type, success, COUNT(*) as count, COUNT(DISTINCT user_id) as unique_users, COUNT(DISTINCT ip_address) as unique_ips FROM security_audit_log WHERE timestamp > ? GROUP BY event_type, success ORDER BY count DESC`, [cutoffDate], (err, rows) => err ? reject(err) : resolve(rows) ); }); } /** * Log system events (startup, shutdown, cleanup, etc.) */ static async logSystemEvent(eventType, success, details = {}) { return this.logAuthEvent(`SYSTEM_${eventType.toUpperCase()}`, null, { success, failureReason: success ? null : (details.error || 'System event failed'), metadata: details }); } /** * Log security incidents (tampering, breaches, etc.) */ static async logSecurityIncident(incidentType, details = {}) { const event = { event_type: `SECURITY_INCIDENT_${incidentType.toUpperCase()}`, user_id: details.userId || null, ip_address: details.ip || 'system', user_agent: details.userAgent || 'system', success: false, failure_reason: `Security incident: ${incidentType}`, metadata: JSON.stringify(details), timestamp: new Date().toISOString() }; try { await new Promise((resolve, reject) => { db.run( `INSERT INTO security_audit_log (event_type, user_id, ip_address, user_agent, success, failure_reason, metadata, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [event.event_type, event.user_id, event.ip_address, event.user_agent, 0, event.failure_reason, event.metadata, event.timestamp], (err) => err ? reject(err) : resolve() ); }); logger.error(`[SECURITY INCIDENT] ${incidentType}: ${JSON.stringify(details)}`); // Aggregate to SIEM with CRITICAL level logAggregator.aggregate('security_audit', 'critical', 'security_incident', `Security incident: ${incidentType}`, { incidentType, ...details }); } catch (error) { logger.error('Failed to log security incident:', error); } } /** * Log admin activities (user management, config changes, etc.) */ static async logAdminActivity(adminId, action, details = {}) { return this.logAuthEvent(`ADMIN_${action.toUpperCase()}`, adminId, { success: true, ip: details.ip, userAgent: details.userAgent, metadata: { action, target: details.target || details.targetUserId, changes: details.changes, ...details } }); } } module.exports = SecurityAuditLogger;