Initial commit: StreamFlow IPTV platform
This commit is contained in:
commit
73a8ae9ffd
1240 changed files with 278451 additions and 0 deletions
565
backend/utils/riskSignatureManager.js
Normal file
565
backend/utils/riskSignatureManager.js
Normal file
|
|
@ -0,0 +1,565 @@
|
|||
/**
|
||||
* 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: '(<script|javascript:|onerror=|onload=|<iframe|eval\\(|alert\\()',
|
||||
match_type: 'regex_case_insensitive',
|
||||
threat_level: 'high',
|
||||
confidence: 0.8,
|
||||
auto_block: 1
|
||||
},
|
||||
{
|
||||
signature_id: 'SIG-ATTACK-PATH-TRAVERSAL',
|
||||
name: 'Path Traversal Pattern',
|
||||
description: 'Directory traversal attack patterns',
|
||||
signature_type: 'attack_pattern',
|
||||
pattern: '(\\.\\./|\\.\\.\\\\/|%2e%2e/|%252e%252e/)',
|
||||
match_type: 'regex_case_insensitive',
|
||||
threat_level: 'high',
|
||||
confidence: 0.9,
|
||||
auto_block: 1
|
||||
},
|
||||
{
|
||||
signature_id: 'SIG-ATTACK-COMMAND-INJECTION',
|
||||
name: 'Command Injection Pattern',
|
||||
description: 'OS command injection patterns',
|
||||
signature_type: 'attack_pattern',
|
||||
pattern: '(;\\s*(rm|cat|ls|wget|curl|bash|sh|cmd|powershell)|\\|\\s*(nc|netcat))',
|
||||
match_type: 'regex_case_insensitive',
|
||||
threat_level: 'critical',
|
||||
confidence: 0.95,
|
||||
auto_block: 1
|
||||
},
|
||||
// Behavioral signatures
|
||||
{
|
||||
signature_id: 'SIG-BEHAVIOR-BRUTE-FORCE',
|
||||
name: 'Brute Force Behavior',
|
||||
description: 'Rapid repeated authentication attempts',
|
||||
signature_type: 'behavior',
|
||||
pattern: 'failed_login_rate',
|
||||
match_type: 'custom',
|
||||
threat_level: 'critical',
|
||||
confidence: 0.9,
|
||||
auto_block: 1
|
||||
},
|
||||
{
|
||||
signature_id: 'SIG-BEHAVIOR-CREDENTIAL-STUFFING',
|
||||
name: 'Credential Stuffing Behavior',
|
||||
description: 'Multiple username attempts from single source',
|
||||
signature_type: 'behavior',
|
||||
pattern: 'unique_username_rate',
|
||||
match_type: 'custom',
|
||||
threat_level: 'high',
|
||||
confidence: 0.85,
|
||||
auto_block: 1
|
||||
},
|
||||
{
|
||||
signature_id: 'SIG-BEHAVIOR-PRIVILEGE-ESC',
|
||||
name: 'Privilege Escalation Behavior',
|
||||
description: 'Repeated unauthorized access attempts',
|
||||
signature_type: 'behavior',
|
||||
pattern: 'authorization_failure_rate',
|
||||
match_type: 'custom',
|
||||
threat_level: 'critical',
|
||||
confidence: 0.95,
|
||||
auto_block: 1
|
||||
},
|
||||
{
|
||||
signature_id: 'SIG-BEHAVIOR-DATA-EXFIL',
|
||||
name: 'Data Exfiltration Behavior',
|
||||
description: 'Unusual data download patterns',
|
||||
signature_type: 'behavior',
|
||||
pattern: 'download_volume_rate',
|
||||
match_type: 'custom',
|
||||
threat_level: 'high',
|
||||
confidence: 0.8,
|
||||
auto_block: 0
|
||||
}
|
||||
];
|
||||
|
||||
for (const signature of defaultSignatures) {
|
||||
await new Promise((resolve, reject) => {
|
||||
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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue