425 lines
10 KiB
JavaScript
425 lines
10 KiB
JavaScript
/**
|
|
* SIEM (Security Information and Event Management) API Routes
|
|
* Provides access to centralized log aggregation, security intelligence,
|
|
* anomaly detection, and real-time alerts
|
|
*/
|
|
|
|
const express = require('express');
|
|
const router = express.Router();
|
|
const { authenticate } = require('../middleware/auth');
|
|
const { requirePermission } = require('../middleware/rbac');
|
|
const { validatePagination, validateIdParam } = require('../middleware/inputValidation');
|
|
const logAggregator = require('../utils/logAggregator');
|
|
const securityIntelligence = require('../utils/securityIntelligence');
|
|
const alertSystem = require('../utils/alertSystem');
|
|
const logger = require('../utils/logger');
|
|
|
|
/**
|
|
* GET /api/siem/logs
|
|
* Query aggregated logs with filtering
|
|
*/
|
|
router.get('/logs',
|
|
authenticate,
|
|
requirePermission('security.view_audit'),
|
|
validatePagination,
|
|
async (req, res) => {
|
|
try {
|
|
const filters = {
|
|
source: req.query.source,
|
|
level: req.query.level,
|
|
category: req.query.category,
|
|
userId: req.query.userId ? parseInt(req.query.userId) : undefined,
|
|
startDate: req.query.startDate,
|
|
endDate: req.query.endDate,
|
|
limit: req.query.limit ? parseInt(req.query.limit) : 100,
|
|
offset: req.query.offset ? parseInt(req.query.offset) : 0
|
|
};
|
|
|
|
const logs = await logAggregator.query(filters);
|
|
|
|
logAggregator.aggregate('siem', 'info', 'access', 'SIEM logs queried', {
|
|
userId: req.user.id,
|
|
filters
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
data: logs,
|
|
filters,
|
|
count: logs.length
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error querying logs:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to query logs',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* POST /api/siem/logs/verify
|
|
* Verify log integrity (check for tampering)
|
|
*/
|
|
router.post('/logs/verify',
|
|
authenticate,
|
|
requirePermission('security.manage'),
|
|
async (req, res) => {
|
|
try {
|
|
const logIds = req.body.logIds || [];
|
|
const result = await logAggregator.verifyIntegrity(logIds.length > 0 ? logIds : null);
|
|
|
|
logAggregator.aggregate('siem', 'info', 'security', 'Log integrity verification performed', {
|
|
userId: req.user.id,
|
|
checkedCount: result.total,
|
|
tamperedCount: result.tampered
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error verifying logs:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to verify log integrity',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/siem/statistics
|
|
* Get log statistics
|
|
*/
|
|
router.get('/statistics',
|
|
authenticate,
|
|
requirePermission('security.view_audit'),
|
|
async (req, res) => {
|
|
try {
|
|
const timeRange = req.query.timeRange ? parseInt(req.query.timeRange) : 24;
|
|
const stats = await logAggregator.getStatistics(timeRange);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: stats,
|
|
timeRange: `${timeRange} hours`
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error getting statistics:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to get statistics',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/siem/export
|
|
* Export logs in JSON or CSV format
|
|
*/
|
|
router.get('/export',
|
|
authenticate,
|
|
requirePermission('security.manage'),
|
|
async (req, res) => {
|
|
try {
|
|
const format = req.query.format || 'json';
|
|
const filters = {
|
|
source: req.query.source,
|
|
level: req.query.level,
|
|
startDate: req.query.startDate,
|
|
endDate: req.query.endDate
|
|
};
|
|
|
|
const exportData = await logAggregator.export(filters, format);
|
|
|
|
logAggregator.aggregate('siem', 'info', 'security', 'Logs exported', {
|
|
userId: req.user.id,
|
|
format,
|
|
filters
|
|
});
|
|
|
|
const contentType = format === 'csv' ? 'text/csv' : 'application/json';
|
|
const filename = `siem_export_${Date.now()}.${format}`;
|
|
|
|
res.setHeader('Content-Type', contentType);
|
|
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
|
|
res.send(exportData);
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error exporting logs:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to export logs',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/siem/anomalies
|
|
* Get detected anomalies
|
|
*/
|
|
router.get('/anomalies',
|
|
authenticate,
|
|
requirePermission('security.view_audit'),
|
|
validatePagination,
|
|
async (req, res) => {
|
|
try {
|
|
const filters = {
|
|
status: req.query.status || 'open',
|
|
severity: req.query.severity,
|
|
type: req.query.type,
|
|
limit: req.query.limit ? parseInt(req.query.limit) : 100,
|
|
offset: req.query.offset ? parseInt(req.query.offset) : 0
|
|
};
|
|
|
|
const anomalies = await securityIntelligence.getAnomalies(filters);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: anomalies,
|
|
count: anomalies.length
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error getting anomalies:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to get anomalies',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* POST /api/siem/anomalies/:id/resolve
|
|
* Resolve an anomaly
|
|
*/
|
|
router.post('/anomalies/:id/resolve',
|
|
authenticate,
|
|
requirePermission('security.manage'),
|
|
validateIdParam,
|
|
async (req, res) => {
|
|
try {
|
|
const anomalyId = req.params.id;
|
|
const notes = req.body.notes || '';
|
|
|
|
await securityIntelligence.resolveAnomaly(anomalyId, req.user.id, notes);
|
|
|
|
logAggregator.aggregate('siem', 'info', 'security', 'Anomaly resolved', {
|
|
userId: req.user.id,
|
|
anomalyId,
|
|
notes
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Anomaly resolved successfully'
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error resolving anomaly:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to resolve anomaly',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/siem/threats
|
|
* Get threat intelligence data
|
|
*/
|
|
router.get('/threats',
|
|
authenticate,
|
|
requirePermission('security.view_audit'),
|
|
validatePagination,
|
|
async (req, res) => {
|
|
try {
|
|
const filters = {
|
|
level: req.query.level,
|
|
type: req.query.type,
|
|
limit: req.query.limit ? parseInt(req.query.limit) : 100
|
|
};
|
|
|
|
const threats = await securityIntelligence.getThreatIntelligence(filters);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: threats,
|
|
count: threats.length
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error getting threats:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to get threat intelligence',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/siem/alerts
|
|
* Get active security alerts
|
|
*/
|
|
router.get('/alerts',
|
|
authenticate,
|
|
requirePermission('security.view_audit'),
|
|
validatePagination,
|
|
async (req, res) => {
|
|
try {
|
|
const filters = {
|
|
status: req.query.status || 'active',
|
|
severity: req.query.severity,
|
|
limit: req.query.limit ? parseInt(req.query.limit) : 100,
|
|
offset: req.query.offset ? parseInt(req.query.offset) : 0
|
|
};
|
|
|
|
const alerts = await alertSystem.getAlerts(filters);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: alerts,
|
|
count: alerts.length
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error getting alerts:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to get alerts',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* POST /api/siem/alerts/:id/acknowledge
|
|
* Acknowledge an alert
|
|
*/
|
|
router.post('/alerts/:id/acknowledge',
|
|
authenticate,
|
|
requirePermission('security.view_audit'),
|
|
validateIdParam,
|
|
async (req, res) => {
|
|
try {
|
|
const alertId = req.params.id;
|
|
const notes = req.body.notes || '';
|
|
|
|
await alertSystem.acknowledgeAlert(alertId, req.user.id, notes);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Alert acknowledged successfully'
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error acknowledging alert:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to acknowledge alert',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* POST /api/siem/alerts/:id/resolve
|
|
* Resolve an alert
|
|
*/
|
|
router.post('/alerts/:id/resolve',
|
|
authenticate,
|
|
requirePermission('security.manage'),
|
|
validateIdParam,
|
|
async (req, res) => {
|
|
try {
|
|
const alertId = req.params.id;
|
|
const notes = req.body.notes;
|
|
|
|
await alertSystem.resolveAlert(alertId, req.user.id, notes);
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Alert resolved successfully'
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error resolving alert:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to resolve alert',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/siem/dashboard
|
|
* Get comprehensive security intelligence dashboard data
|
|
*/
|
|
router.get('/dashboard',
|
|
authenticate,
|
|
requirePermission('security.view_audit'),
|
|
async (req, res) => {
|
|
try {
|
|
const [dashboardData, alertStats] = await Promise.all([
|
|
securityIntelligence.getDashboardData(),
|
|
alertSystem.getStatistics()
|
|
]);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
...dashboardData,
|
|
alertStats
|
|
}
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error getting dashboard data:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to get dashboard data',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
/**
|
|
* GET /api/siem/alert-rules
|
|
* Get configured alert rules
|
|
*/
|
|
router.get('/alert-rules',
|
|
authenticate,
|
|
requirePermission('security.manage'),
|
|
async (req, res) => {
|
|
try {
|
|
const rules = Array.from(alertSystem.alertRules.values());
|
|
|
|
res.json({
|
|
success: true,
|
|
data: rules,
|
|
count: rules.length
|
|
});
|
|
} catch (error) {
|
|
logger.error('[SIEM API] Error getting alert rules:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Failed to get alert rules',
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
);
|
|
|
|
module.exports = router;
|