Automatizarea Raspunsului la Incidente cu n8n: Construirea Playbook-urilor de Securitate
Automatizarea raspunsului la incidente reduce timpul mediu de detectie si raspuns la amenintarile de securitate. Acest ghid arata cum sa construiesti playbook-uri de securitate complete cu n8n.
Ingestia si Triajul Alertelor
Colector de Alerte Multi-Sursa
// n8n Function Node - Normalizator de Alerte
const rawAlert = $input.first().json;
const sourceType = rawAlert.source || 'unknown';
// Normalizeaza alertele din diferite surse intr-un format comun
const normalizers = {
splunk: (alert) => ({
id: alert.sid || `splunk_${Date.now()}`,
source: 'splunk',
timestamp: alert.trigger_time || new Date().toISOString(),
title: alert.search_name,
description: alert.description || alert.search_name,
severity: mapSplunkSeverity(alert.severity),
category: alert.category || 'unknown',
raw_data: alert.result || {},
indicators: extractIndicators(alert.result)
}),
crowdstrike: (alert) => ({
id: alert.detection_id,
source: 'crowdstrike',
timestamp: alert.created_timestamp,
title: alert.tactic + ': ' + alert.technique,
description: alert.description,
severity: mapCrowdstrikeSeverity(alert.max_severity),
category: 'endpoint',
raw_data: alert,
indicators: {
hostnames: [alert.device?.hostname],
ips: [alert.device?.local_ip],
users: [alert.user_name],
processes: [alert.process?.file_name],
hashes: [alert.process?.sha256]
}
}),
palo_alto: (alert) => ({
id: alert.seqno || `pan_${Date.now()}`,
source: 'palo_alto',
timestamp: alert.receive_time,
title: alert.threatid_name || alert.rule,
description: alert.misc || alert.threatid_name,
severity: mapPaloAltoSeverity(alert.severity),
category: alert.type || 'network',
raw_data: alert,
indicators: {
src_ip: alert.src,
dst_ip: alert.dst,
src_port: alert.sport,
dst_port: alert.dport,
url: alert.url,
application: alert.app
}
}),
azure_sentinel: (alert) => ({
id: alert.SystemAlertId,
source: 'azure_sentinel',
timestamp: alert.TimeGenerated,
title: alert.AlertName,
description: alert.Description,
severity: alert.AlertSeverity.toLowerCase(),
category: alert.Category,
raw_data: alert,
indicators: {
entities: alert.Entities,
tactics: alert.Tactics,
techniques: alert.Techniques
}
}),
custom_webhook: (alert) => ({
id: alert.alert_id || `custom_${Date.now()}`,
source: alert.source_name || 'custom',
timestamp: alert.timestamp || new Date().toISOString(),
title: alert.title,
description: alert.description,
severity: alert.severity || 'medium',
category: alert.category || 'custom',
raw_data: alert,
indicators: alert.indicators || {}
})
};
function mapSplunkSeverity(severity) {
const mapping = { '1': 'info', '2': 'low', '3': 'medium', '4': 'high', '5': 'critical' };
return mapping[severity] || 'medium';
}
function mapCrowdstrikeSeverity(severity) {
if (severity >= 80) return 'critical';
if (severity >= 60) return 'high';
if (severity >= 40) return 'medium';
if (severity >= 20) return 'low';
return 'info';
}
function mapPaloAltoSeverity(severity) {
const mapping = {
'informational': 'info',
'low': 'low',
'medium': 'medium',
'high': 'high',
'critical': 'critical'
};
return mapping[severity?.toLowerCase()] || 'medium';
}
function extractIndicators(data) {
const indicators = {
ips: [],
domains: [],
hashes: [],
emails: [],
urls: []
};
const text = JSON.stringify(data);
// Extrage IP-uri
const ipRegex = /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g;
indicators.ips = [...new Set(text.match(ipRegex) || [])];
// Extrage domenii
const domainRegex = /\b(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}\b/gi;
indicators.domains = [...new Set(text.match(domainRegex) || [])];
// Extrage hash-uri (MD5, SHA1, SHA256)
const hashRegex = /\b[a-fA-F0-9]{32}\b|\b[a-fA-F0-9]{40}\b|\b[a-fA-F0-9]{64}\b/g;
indicators.hashes = [...new Set(text.match(hashRegex) || [])];
return indicators;
}
// Normalizeaza alerta primita
const normalizer = normalizers[sourceType] || normalizers.custom_webhook;
const normalizedAlert = normalizer(rawAlert);
// Adauga metadata de imbogatire
normalizedAlert.received_at = new Date().toISOString();
normalizedAlert.status = 'new';
normalizedAlert.workflow_id = $execution.id;
return { json: normalizedAlert };Triajul si Prioritizarea Alertelor
// n8n Function Node - Motor de Triaj Alerte
const alert = $input.first().json;
// Configuratia triajului
const triageConfig = {
severityWeights: {
critical: 100,
high: 75,
medium: 50,
low: 25,
info: 10
},
categoryWeights: {
ransomware: 50,
data_exfiltration: 45,
malware: 40,
intrusion: 35,
phishing: 30,
authentication: 25,
network: 20,
endpoint: 15,
custom: 10,
unknown: 5
},
assetCriticality: {
'domain_controller': 50,
'database_server': 45,
'web_server': 30,
'workstation': 15,
'unknown': 10
},
timeDecay: {
enabled: true,
halfLife: 3600000 // 1 ora in ms
}
};
// Calculeaza scorul de prioritate
function calculatePriorityScore(alert, config) {
let score = 0;
// Scor de severitate de baza
score += config.severityWeights[alert.severity] || 25;
// Pondere categorie
score += config.categoryWeights[alert.category] || 10;
// Criticitatea asset-ului (daca e disponibila)
const assetType = alert.raw_data?.asset_type || 'unknown';
score += config.assetCriticality[assetType] || 10;
// Bonus pentru indicatori multipli
const indicatorCount = Object.values(alert.indicators || {})
.flat()
.filter(i => i).length;
if (indicatorCount > 5) score += 20;
else if (indicatorCount > 2) score += 10;
// Degradare temporala pentru alertele mai vechi
if (config.timeDecay.enabled) {
const alertAge = Date.now() - new Date(alert.timestamp).getTime();
const decayFactor = Math.exp(-alertAge / config.timeDecay.halfLife);
score = score * (0.5 + 0.5 * decayFactor);
}
return Math.round(score);
}
// Determina actiunile de raspuns pe baza triajului
function determineResponseActions(alert, score) {
const actions = [];
// Severitatea critica si inalta primesc atentie imediata
if (alert.severity === 'critical' || score >= 150) {
actions.push({
type: 'escalate',
target: 'security_lead',
urgency: 'immediate'
});
actions.push({
type: 'page',
target: 'on_call',
message: `Alerta critica: ${alert.title}`
});
}
// Auto-imbogatire pentru toate alertele
actions.push({
type: 'enrich',
sources: ['virustotal', 'shodan', 'abuseipdb']
});
// Auto-izolare pentru categorii specifice
if (['ransomware', 'malware'].includes(alert.category)) {
actions.push({
type: 'containment',
action: 'isolate_endpoint',
target: alert.indicators?.hostnames?.[0]
});
}
// Creeaza ticket pentru urmarire
actions.push({
type: 'create_ticket',
priority: score >= 100 ? 'high' : score >= 50 ? 'medium' : 'low'
});
return actions;
}
// Verifica corelatia cu incidentele existente
function checkCorrelation(alert, existingAlerts) {
const correlations = [];
for (const existing of existingAlerts) {
// Acelasi IP sursa
const alertIPs = alert.indicators?.ips || [];
const existingIPs = existing.indicators?.ips || [];
const ipOverlap = alertIPs.filter(ip => existingIPs.includes(ip));
if (ipOverlap.length > 0) {
correlations.push({
type: 'ip_correlation',
related_alert: existing.id,
matching_ips: ipOverlap
});
}
// Acelasi host
const alertHosts = alert.indicators?.hostnames || [];
const existingHosts = existing.indicators?.hostnames || [];
const hostOverlap = alertHosts.filter(h => existingHosts.includes(h));
if (hostOverlap.length > 0) {
correlations.push({
type: 'host_correlation',
related_alert: existing.id,
matching_hosts: hostOverlap
});
}
// Cadru temporal similar (in decurs de 1 ora)
const timeDiff = Math.abs(
new Date(alert.timestamp) - new Date(existing.timestamp)
);
if (timeDiff < 3600000) {
correlations.push({
type: 'temporal_correlation',
related_alert: existing.id,
time_difference_ms: timeDiff
});
}
}
return correlations;
}
// Obtine alertele existente din context (ar veni de la nodul anterior)
const existingAlerts = $('Get Recent Alerts').all().map(i => i.json);
// Efectueaza triajul
const priorityScore = calculatePriorityScore(alert, triageConfig);
const responseActions = determineResponseActions(alert, priorityScore);
const correlations = checkCorrelation(alert, existingAlerts);
// Construieste rezultatul triajului
const triageResult = {
alert: alert,
triage: {
priority_score: priorityScore,
priority_level: priorityScore >= 150 ? 'P1' :
priorityScore >= 100 ? 'P2' :
priorityScore >= 50 ? 'P3' : 'P4',
response_actions: responseActions,
correlations: correlations,
correlation_count: correlations.length,
is_correlated: correlations.length > 0,
triaged_at: new Date().toISOString()
}
};
return { json: triageResult };Imbogatirea Indicatorilor
// n8n Function Node - Agregator de Imbogatire
const triageResult = $input.first().json;
const alert = triageResult.alert;
// Colecteaza rezultatele de imbogatire din query-urile paralele
const vtResults = $('VirusTotal Query').first()?.json || {};
const shodanResults = $('Shodan Query').first()?.json || {};
const abuseResults = $('AbuseIPDB Query').first()?.json || {};
const internalResults = $('Internal Asset Lookup').first()?.json || {};
// Proceseaza imbogatirile
const enrichments = {
threat_intel: {
virustotal: processVirusTotalResults(vtResults),
shodan: processShodanResults(shodanResults),
abuseipdb: processAbuseIPDBResults(abuseResults)
},
internal: {
asset_info: internalResults.asset || null,
user_info: internalResults.user || null,
recent_activity: internalResults.activity || []
},
risk_indicators: [],
enriched_at: new Date().toISOString()
};
function processVirusTotalResults(results) {
if (!results.data) return null;
const data = results.data.attributes || {};
return {
reputation: data.reputation,
malicious_count: data.last_analysis_stats?.malicious || 0,
suspicious_count: data.last_analysis_stats?.suspicious || 0,
harmless_count: data.last_analysis_stats?.harmless || 0,
categories: data.categories,
last_analysis_date: data.last_analysis_date,
is_malicious: (data.last_analysis_stats?.malicious || 0) > 3
};
}
function processShodanResults(results) {
if (!results.ip) return null;
return {
ip: results.ip,
organization: results.org,
country: results.country_name,
city: results.city,
asn: results.asn,
open_ports: results.ports || [],
hostnames: results.hostnames || [],
vulnerabilities: results.vulns || [],
is_cloud: isCloudProvider(results.org),
is_vpn: isVPNProvider(results.org)
};
}
function processAbuseIPDBResults(results) {
if (!results.data) return null;
const data = results.data;
return {
ip: data.ipAddress,
abuse_confidence: data.abuseConfidenceScore,
is_public: data.isPublic,
is_whitelisted: data.isWhitelisted,
country: data.countryCode,
isp: data.isp,
domain: data.domain,
total_reports: data.totalReports,
last_reported_at: data.lastReportedAt,
is_abusive: data.abuseConfidenceScore > 50
};
}
function isCloudProvider(org) {
const cloudProviders = ['amazon', 'aws', 'google', 'microsoft', 'azure', 'digitalocean'];
return cloudProviders.some(p => org?.toLowerCase().includes(p));
}
function isVPNProvider(org) {
const vpnProviders = ['nordvpn', 'expressvpn', 'private internet', 'mullvad'];
return vpnProviders.some(p => org?.toLowerCase().includes(p));
}
// Calculeaza indicatorii de risc pe baza imbogatirilor
function calculateRiskIndicators(enrichments) {
const indicators = [];
// Indicatori VirusTotal
if (enrichments.threat_intel.virustotal?.is_malicious) {
indicators.push({
type: 'known_malicious',
source: 'virustotal',
severity: 'high',
description: 'Indicatorul a fost marcat ca malitios de mai multe motoare AV'
});
}
// Indicatori Shodan
const shodan = enrichments.threat_intel.shodan;
if (shodan?.vulnerabilities?.length > 0) {
indicators.push({
type: 'known_vulnerabilities',
source: 'shodan',
severity: 'medium',
description: `Host-ul are ${shodan.vulnerabilities.length} vulnerabilitati cunoscute`
});
}
// Indicatori AbuseIPDB
if (enrichments.threat_intel.abuseipdb?.is_abusive) {
indicators.push({
type: 'abuse_reported',
source: 'abuseipdb',
severity: 'high',
description: `IP raportat pentru abuz (incredere: ${enrichments.threat_intel.abuseipdb.abuse_confidence}%)`
});
}
// Indicatori VPN/Cloud
if (shodan?.is_vpn) {
indicators.push({
type: 'vpn_detected',
source: 'shodan',
severity: 'low',
description: 'Traficul provine de la un furnizor VPN cunoscut'
});
}
return indicators;
}
enrichments.risk_indicators = calculateRiskIndicators(enrichments);
// Actualizeaza triajul cu imbogatire
const enrichedResult = {
...triageResult,
enrichments: enrichments,
enrichment_summary: {
sources_queried: 4,
risk_indicator_count: enrichments.risk_indicators.length,
high_risk_indicators: enrichments.risk_indicators.filter(i => i.severity === 'high').length,
is_known_malicious: enrichments.threat_intel.virustotal?.is_malicious ||
enrichments.threat_intel.abuseipdb?.is_abusive
}
};
return { json: enrichedResult };Actiuni Automate de Raspuns
Actiuni de Izolare
// n8n Function Node - Motor de Decizie Izolare
const enrichedAlert = $input.first().json;
const alert = enrichedAlert.alert;
const triage = enrichedAlert.triage;
const enrichments = enrichedAlert.enrichments;
// Configuratia politicii de izolare
const containmentPolicy = {
auto_contain: {
enabled: true,
conditions: {
min_priority_score: 100,
require_malicious_confirmation: true,
excluded_assets: ['domain_controller', 'critical_server'],
business_hours_only: false
}
},
actions: {
isolate_endpoint: {
enabled: true,
providers: ['crowdstrike', 'carbon_black', 'sentinel_one']
},
block_ip: {
enabled: true,
firewalls: ['palo_alto', 'fortinet']
},
disable_user: {
enabled: true,
idp: 'okta'
},
quarantine_email: {
enabled: true,
provider: 'microsoft_365'
}
}
};
// Determina actiunile de izolare
function determineContainmentActions(alert, triage, enrichments, policy) {
const actions = [];
// Verifica daca auto-izolarea e activata si conditiile sunt indeplinite
if (!policy.auto_contain.enabled) {
return [{
type: 'manual_review',
reason: 'Auto-izolarea dezactivata',
recommended_actions: suggestContainmentActions(alert, enrichments)
}];
}
// Verifica pragul de prioritate
if (triage.priority_score < policy.auto_contain.conditions.min_priority_score) {
return [{
type: 'monitor_only',
reason: 'Prioritatea sub pragul de izolare',
priority_score: triage.priority_score,
threshold: policy.auto_contain.conditions.min_priority_score
}];
}
// Verifica confirmarea de malitios daca e necesara
if (policy.auto_contain.conditions.require_malicious_confirmation) {
if (!enrichments.enrichment_summary.is_known_malicious) {
return [{
type: 'pending_confirmation',
reason: 'Se asteapta confirmarea de malitios',
recommended_actions: suggestContainmentActions(alert, enrichments)
}];
}
}
// Verifica asset-urile excluse
const assetType = enrichments.internal.asset_info?.type;
if (policy.auto_contain.conditions.excluded_assets.includes(assetType)) {
return [{
type: 'manual_review',
reason: `Tipul de asset '${assetType}' exclus din auto-izolare`,
recommended_actions: suggestContainmentActions(alert, enrichments)
}];
}
// Determina actiuni specifice de izolare pe baza tipului de alerta
if (alert.category === 'endpoint' || alert.category === 'malware') {
const hostname = alert.indicators?.hostnames?.[0];
if (hostname && policy.actions.isolate_endpoint.enabled) {
actions.push({
type: 'isolate_endpoint',
target: hostname,
provider: policy.actions.isolate_endpoint.providers[0],
severity: 'high',
reversible: true
});
}
}
// Blocheaza IP-urile malitioase
const maliciousIPs = (alert.indicators?.ips || []).filter(ip => {
// Verifica daca IP-ul e confirmat malitios
return enrichments.threat_intel.abuseipdb?.is_abusive ||
enrichments.threat_intel.virustotal?.is_malicious;
});
if (maliciousIPs.length > 0 && policy.actions.block_ip.enabled) {
for (const ip of maliciousIPs) {
actions.push({
type: 'block_ip',
target: ip,
firewall: policy.actions.block_ip.firewalls[0],
duration: 86400, // 24 ore
reversible: true
});
}
}
// Dezactiveaza utilizatorul compromis
if (alert.category === 'authentication' || alert.category === 'phishing') {
const user = alert.indicators?.users?.[0];
if (user && policy.actions.disable_user.enabled) {
actions.push({
type: 'disable_user',
target: user,
provider: policy.actions.disable_user.idp,
reason: `Incident de securitate: ${alert.id}`,
reversible: true
});
}
}
return actions;
}
function suggestContainmentActions(alert, enrichments) {
const suggestions = [];
if (alert.indicators?.hostnames?.length > 0) {
suggestions.push({
action: 'isolate_endpoint',
target: alert.indicators.hostnames[0],
justification: 'Endpoint-ul poate fi compromis'
});
}
if (alert.indicators?.ips?.length > 0) {
suggestions.push({
action: 'block_ip',
target: alert.indicators.ips[0],
justification: 'Activitate de retea suspecta detectata'
});
}
return suggestions;
}
// Executa decizia de izolare
const containmentActions = determineContainmentActions(
alert,
triage,
enrichments,
containmentPolicy
);
const containmentResult = {
...enrichedAlert,
containment: {
decision_time: new Date().toISOString(),
actions: containmentActions,
auto_contained: containmentActions.some(a =>
['isolate_endpoint', 'block_ip', 'disable_user'].includes(a.type)
),
requires_manual_review: containmentActions.some(a =>
['manual_review', 'pending_confirmation'].includes(a.type)
)
}
};
// Output pe cai diferite pentru automatizare vs. revizuire manuala
if (containmentResult.containment.auto_contained) {
return [{ json: { ...containmentResult, path: 'auto_response' } }];
} else {
return [{ json: { ...containmentResult, path: 'manual_review' } }];
}Notificare si Escaladare
// n8n Function Node - Constructor de Notificari
const incidentData = $input.first().json;
const alert = incidentData.alert;
const triage = incidentData.triage;
const containment = incidentData.containment;
// Construieste notificari pentru diferite canale
const notifications = {
slack: buildSlackNotification(incidentData),
email: buildEmailNotification(incidentData),
pagerduty: buildPagerDutyNotification(incidentData),
teams: buildTeamsNotification(incidentData),
ticket: buildTicketContent(incidentData)
};
function buildSlackNotification(data) {
const severityEmoji = {
critical: '🔴',
high: '🟠',
medium: '🟡',
low: '🟢',
info: '🔵'
};
const blocks = [
{
type: 'header',
text: {
type: 'plain_text',
text: `${severityEmoji[data.alert.severity]} Alerta Securitate: ${data.alert.title}`
}
},
{
type: 'section',
fields: [
{ type: 'mrkdwn', text: `*Severitate:*\n${data.alert.severity.toUpperCase()}` },
{ type: 'mrkdwn', text: `*Prioritate:*\n${data.triage.priority_level}` },
{ type: 'mrkdwn', text: `*Sursa:*\n${data.alert.source}` },
{ type: 'mrkdwn', text: `*Categorie:*\n${data.alert.category}` }
]
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*Descriere:*\n${data.alert.description}`
}
}
];
// Adauga indicatori
if (Object.keys(data.alert.indicators || {}).length > 0) {
const indicatorText = Object.entries(data.alert.indicators)
.filter(([k, v]) => v && (Array.isArray(v) ? v.length > 0 : true))
.map(([k, v]) => `• *${k}:* ${Array.isArray(v) ? v.join(', ') : v}`)
.join('\n');
blocks.push({
type: 'section',
text: { type: 'mrkdwn', text: `*Indicatori:*\n${indicatorText}` }
});
}
// Adauga actiuni de izolare
if (data.containment?.actions?.length > 0) {
const actionText = data.containment.actions
.map(a => `• ${a.type}: ${a.target || 'N/A'} (${a.type === 'manual_review' ? '⚠️ Manual' : '✅ Auto'})`)
.join('\n');
blocks.push({
type: 'section',
text: { type: 'mrkdwn', text: `*Actiuni de Raspuns:*\n${actionText}` }
});
}
// Adauga butoane de actiune
blocks.push({
type: 'actions',
elements: [
{
type: 'button',
text: { type: 'plain_text', text: '📋 Vezi Detalii' },
url: `https://siem.company.com/alerts/${data.alert.id}`,
action_id: 'view_details'
},
{
type: 'button',
text: { type: 'plain_text', text: '✅ Confirma' },
style: 'primary',
action_id: 'acknowledge',
value: data.alert.id
},
{
type: 'button',
text: { type: 'plain_text', text: '🚨 Escaleaza' },
style: 'danger',
action_id: 'escalate',
value: data.alert.id
}
]
});
return {
channel: getSlackChannel(data.triage.priority_level),
blocks: blocks,
text: `Alerta Securitate: ${data.alert.title}` // Fallback
};
}
function buildEmailNotification(data) {
return {
to: getEmailRecipients(data.triage.priority_level),
subject: `[${data.alert.severity.toUpperCase()}] Alerta Securitate: ${data.alert.title}`,
html: `
<h2>Alerta de Securitate</h2>
<p><strong>ID Alerta:</strong> ${data.alert.id}</p>
<p><strong>Severitate:</strong> ${data.alert.severity}</p>
<p><strong>Prioritate:</strong> ${data.triage.priority_level}</p>
<p><strong>Sursa:</strong> ${data.alert.source}</p>
<p><strong>Categorie:</strong> ${data.alert.category}</p>
<p><strong>Descriere:</strong> ${data.alert.description}</p>
<h3>Indicatori</h3>
<ul>
${Object.entries(data.alert.indicators || {})
.filter(([k, v]) => v && (Array.isArray(v) ? v.length > 0 : true))
.map(([k, v]) => `<li><strong>${k}:</strong> ${Array.isArray(v) ? v.join(', ') : v}</li>`)
.join('')}
</ul>
<h3>Actiuni de Raspuns</h3>
<ul>
${(data.containment?.actions || [])
.map(a => `<li>${a.type}: ${a.target || 'N/A'}</li>`)
.join('')}
</ul>
<p><a href="https://siem.company.com/alerts/${data.alert.id}">Vezi in SIEM</a></p>
`
};
}
function buildPagerDutyNotification(data) {
return {
routing_key: process.env.PAGERDUTY_ROUTING_KEY,
event_action: 'trigger',
dedup_key: data.alert.id,
payload: {
summary: `${data.alert.severity.toUpperCase()}: ${data.alert.title}`,
severity: mapToPagerDutySeverity(data.alert.severity),
source: data.alert.source,
timestamp: data.alert.timestamp,
custom_details: {
alert_id: data.alert.id,
category: data.alert.category,
priority: data.triage.priority_level,
indicators: data.alert.indicators
}
},
links: [{
href: `https://siem.company.com/alerts/${data.alert.id}`,
text: 'Vezi in SIEM'
}]
};
}
function buildTeamsNotification(data) {
return {
'@type': 'MessageCard',
'@context': 'http://schema.org/extensions',
themeColor: getSeverityColor(data.alert.severity),
summary: `Alerta Securitate: ${data.alert.title}`,
sections: [{
activityTitle: `Alerta Securitate: ${data.alert.title}`,
facts: [
{ name: 'Severitate', value: data.alert.severity },
{ name: 'Prioritate', value: data.triage.priority_level },
{ name: 'Sursa', value: data.alert.source },
{ name: 'Categorie', value: data.alert.category }
],
text: data.alert.description
}],
potentialAction: [{
'@type': 'OpenUri',
name: 'Vezi Detalii',
targets: [{ os: 'default', uri: `https://siem.company.com/alerts/${data.alert.id}` }]
}]
};
}
function buildTicketContent(data) {
return {
title: `[${data.alert.severity.toUpperCase()}] ${data.alert.title}`,
description: `
## Detalii Alerta
- **ID Alerta:** ${data.alert.id}
- **Sursa:** ${data.alert.source}
- **Categorie:** ${data.alert.category}
- **Severitate:** ${data.alert.severity}
- **Prioritate:** ${data.triage.priority_level}
- **Timestamp:** ${data.alert.timestamp}
## Descriere
${data.alert.description}
## Indicatori
${Object.entries(data.alert.indicators || {})
.filter(([k, v]) => v && (Array.isArray(v) ? v.length > 0 : true))
.map(([k, v]) => `- **${k}:** ${Array.isArray(v) ? v.join(', ') : v}`)
.join('\n')}
## Sumar Imbogatire
- Surse Interogate: ${data.enrichments?.enrichment_summary?.sources_queried || 0}
- Indicatori de Risc: ${data.enrichments?.enrichment_summary?.risk_indicator_count || 0}
- Malitios Cunoscut: ${data.enrichments?.enrichment_summary?.is_known_malicious ? 'Da' : 'Nu'}
## Actiuni de Raspuns
${(data.containment?.actions || [])
.map(a => `- ${a.type}: ${a.target || 'N/A'}`)
.join('\n')}
`,
priority: mapToTicketPriority(data.triage.priority_level),
assignee: getAssignee(data.triage.priority_level),
labels: [
'security',
data.alert.category,
data.alert.severity
]
};
}
function getSlackChannel(priority) {
const channels = {
'P1': '#security-critical',
'P2': '#security-high',
'P3': '#security-alerts',
'P4': '#security-low'
};
return channels[priority] || '#security-alerts';
}
function getEmailRecipients(priority) {
const recipients = {
'P1': ['security-team@company.com', 'ciso@company.com'],
'P2': ['security-team@company.com'],
'P3': ['security-analysts@company.com'],
'P4': ['security-analysts@company.com']
};
return recipients[priority] || ['security-analysts@company.com'];
}
function mapToPagerDutySeverity(severity) {
const mapping = {
'critical': 'critical',
'high': 'error',
'medium': 'warning',
'low': 'info',
'info': 'info'
};
return mapping[severity] || 'warning';
}
function getSeverityColor(severity) {
const colors = {
'critical': 'FF0000',
'high': 'FF8C00',
'medium': 'FFD700',
'low': '32CD32',
'info': '1E90FF'
};
return colors[severity] || 'FFD700';
}
function mapToTicketPriority(priority) {
return priority; // Mapare P1, P2, P3, P4
}
function getAssignee(priority) {
return priority === 'P1' ? 'security-lead' : 'security-triage';
}
return {
json: {
...incidentData,
notifications: notifications
}
};Bune Practici
Design-ul Playbook-urilor
- Incepe simplu: Incepe cu triaj de baza si escaladare
- Itereaza: Adauga automatizare pe baza feedback-ului analistilor
- Testeaza temeinic: Foloseste alerte simulate pentru a verifica comportamentul playbook-ului
- Documenteaza deciziile: Logheaza toate actiunile automate pentru revizuire
Sfaturi de Integrare
- Foloseste webhook-uri pentru ingestia alertelor in timp real
- Implementeaza logica de retry pentru apelurile API externe
- Stocheaza in cache rezultatele de imbogatire pentru a reduce costurile API
- Foloseste connection pooling pentru query-uri la baza de date
Consideratii de Securitate
- Stocare securizata a credentialelor folosind sistemul de credentiale n8n
- Implementeaza rate limiting pe actiunile de izolare
- Cere aprobare pentru izolari cu impact ridicat
- Mentine un audit trail al tuturor actiunilor automate
Automatizarea raspunsului la incidente cu n8n reduce semnificativ timpul de raspuns, mentinand in acelasi timp supravegherea umana necesara pentru decizii complexe de securitate.
Sistemul tau AI e conform cu EU AI Act? Evaluare gratuita de risc - afla in 2 minute →