nis2-agile/public/integrations/siem.html
DevEnv nis2-agile 86e9bdded2 [FEAT] Services API, Webhook, Whistleblowing, Normative + integrazioni
Sprint completo — prodotto presentation-ready:

Services API (read-only, API Key + scope):
- GET /api/services/status|compliance-summary|risks-feed|incidents-feed
- GET /api/services/controls-status|assets-critical|suppliers-risk|policies-approved
- GET /api/services/openapi (spec OpenAPI 3.0.3 JSON)

Webhook Outbound (Stripe-like HMAC-SHA256):
- CRUD api_keys + webhook_subscriptions (Settings → 2 nuovi tab)
- WebhookService: retry 3x backoff (0s/5min/30min), delivery log
- Trigger auto in IncidentController, RiskController, PolicyController
- Delivery log, test ping, processRetry

Nuovi moduli:
- WhistleblowingController (Art.32 NIS2): anonimato garantito, timeline, token tracking
- NormativeController: feed NIS2/ACN/DORA con ACK tracciato per audit

Frontend:
- whistleblowing.html: form submit anonimo/firmato + gestione CISO
- normative.html: feed con presa visione documentata + progress bar ACK
- public/docs/api.html: documentazione API dark theme (Swagger-like)
- settings.html: tab API Keys + tab Webhook
- integrations/: guide per lg231, SustainAI, AllRisk, SIEM (widget + codice)
- Sidebar: Segnalazioni + Normative aggiunte a common.js

DB: migration 007 (api_keys, webhook_subscriptions, webhook_deliveries),
    008 (whistleblowing_reports + timeline),
    009 (normative_updates + normative_ack + seed NIS2/ACN/DORA/ISO)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 13:20:24 +01:00

180 lines
9.9 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SIEM × NIS2 Agile — Integrazione</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--primary: #06b6d4; --purple: #8b5cf6;
--gray-200: #e2e8f0; --gray-500: #64748b; --gray-700: #334155;
--radius: 8px; --font: -apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
--mono: 'Cascadia Code','Consolas',monospace;
}
body { background: #f8fafc; font-family: var(--font); color: #0f172a; }
.header { background: linear-gradient(135deg, #2e1065, #3b0764); padding: 40px 48px; color: #fff; }
.header-badges { display: flex; gap: 10px; margin-bottom: 16px; }
.badge { padding: 4px 12px; border-radius: 20px; font-size: 0.75rem; font-weight: 700; }
.badge-nis2 { background: rgba(6,182,212,0.2); color: #67e8f9; border: 1px solid rgba(6,182,212,0.3); }
.badge-siem { background: rgba(139,92,246,0.2); color: #ddd6fe; border: 1px solid rgba(139,92,246,0.3); }
h1 { font-size: 1.875rem; font-weight: 800; margin-bottom: 8px; }
.header p { color: #ddd6fe; font-size: 1rem; }
.container { max-width: 960px; margin: 0 auto; padding: 40px 24px; }
h2 { font-size: 1.25rem; font-weight: 700; margin-bottom: 12px; padding-bottom: 10px; border-bottom: 2px solid var(--gray-200); }
.section { margin-bottom: 48px; }
p { color: var(--gray-500); font-size: 0.9rem; line-height: 1.7; margin-bottom: 12px; }
pre { background: #1e293b; color: #e2e8f0; padding: 20px; border-radius: var(--radius); font-family: var(--mono); font-size: 0.8125rem; overflow-x: auto; line-height: 1.7; margin: 12px 0; }
code { background: #f1f5f9; padding: 2px 6px; border-radius: 4px; font-family: var(--mono); font-size: 0.85em; }
.siem-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; margin-top: 16px; }
.siem-card { background: #fff; border: 1px solid var(--gray-200); border-radius: var(--radius); padding: 16px; }
.siem-card h4 { font-size: 0.875rem; font-weight: 700; margin-bottom: 6px; }
.siem-card p { font-size: 0.8rem; color: var(--gray-500); margin: 0; }
.info-box { padding: 14px 16px; border-radius: var(--radius); margin: 16px 0; font-size: 0.875rem; }
.info-purple { background: #f5f3ff; border-left: 3px solid var(--purple); color: #4c1d95; }
</style>
</head>
<body>
<div class="header">
<div class="header-badges">
<span class="badge badge-siem">SIEM / SOC</span>
<span>×</span>
<span class="badge badge-nis2">NIS2 Agile</span>
</div>
<h1>Integrazione SIEM / SOC ← NIS2 Agile</h1>
<p>Ricevi eventi NIS2 in tempo reale nel tuo SIEM. Incidenti Art.23, rischi HIGH/CRITICAL, variazioni compliance come alert automatici.</p>
</div>
<div class="container">
<div class="section">
<h2>SIEM supportati</h2>
<div class="siem-grid">
<div class="siem-card"><h4>Splunk Enterprise</h4><p>HTTP Event Collector (HEC) + custom TA per NIS2 Agile. Dashboard Art.23 precompilata.</p></div>
<div class="siem-card"><h4>Elastic SIEM</h4><p>Logstash HTTP input + index template NIS2. Alert rule per incident.significant.</p></div>
<div class="siem-card"><h4>IBM QRadar</h4><p>Universal DSM + webhook-to-syslog bridge. Evento NIS2 → offense QRadar.</p></div>
<div class="siem-card"><h4>Microsoft Sentinel</h4><p>Logic App webhook receiver → Azure Monitor. Playbook SOAR per Art.23.</p></div>
</div>
</div>
<div class="section">
<h2>Configurazione Webhook NIS2 → SIEM</h2>
<p>Configura in NIS2 Agile → Settings → Webhook l'endpoint del tuo SIEM:</p>
<pre><span style="color:#7dd3fc;"># SIEM HEC / HTTP Input endpoint</span>
URL: https://your-siem.example.com:8088/services/collector <span style="color:#7dd3fc;"># Splunk HEC</span>
URL: https://your-elk.example.com:9200/_ingest/pipeline/nis2 <span style="color:#7dd3fc;"># Elastic</span>
Events: incident.created, incident.significant, incident.deadline_warning,
risk.high_created, compliance.score_changed</pre>
</div>
<div class="section">
<h2>Splunk HEC — Bridge PHP</h2>
<p>Se il SIEM non supporta nativamente la firma HMAC-SHA256, usa questo bridge come proxy tra NIS2 e Splunk HEC:</p>
<pre><span style="color:#7dd3fc;">// nis2_to_splunk_bridge.php — Deploy su server intermedio</span>
<span style="color:#f1fa8c;">$nis2Secret</span> = getenv(<span style="color:#86efac;">'NIS2_WEBHOOK_SECRET'</span>);
<span style="color:#f1fa8c;">$splunkHec</span> = getenv(<span style="color:#86efac;">'SPLUNK_HEC_URL'</span>); <span style="color:#7dd3fc;">// https://splunk:8088/services/collector</span>
<span style="color:#f1fa8c;">$splunkToken</span> = getenv(<span style="color:#86efac;">'SPLUNK_HEC_TOKEN'</span>);
<span style="color:#7dd3fc;">// 1. Verifica firma NIS2</span>
<span style="color:#f1fa8c;">$body</span> = file_get_contents(<span style="color:#86efac;">'php://input'</span>);
<span style="color:#f1fa8c;">$sig</span> = $_SERVER[<span style="color:#86efac;">'HTTP_X_NIS2_SIGNATURE'</span>] ?? <span style="color:#86efac;">''</span>;
if (!hash_equals(<span style="color:#86efac;">'sha256='</span> . hash_hmac(<span style="color:#86efac;">'sha256'</span>, <span style="color:#f1fa8c;">$body</span>, <span style="color:#f1fa8c;">$nis2Secret</span>), <span style="color:#f1fa8c;">$sig</span>)) {
http_response_code(401); exit;
}
<span style="color:#f1fa8c;">$payload</span> = json_decode(<span style="color:#f1fa8c;">$body</span>, true);
<span style="color:#7dd3fc;">// 2. Trasforma in formato Splunk HEC</span>
<span style="color:#f1fa8c;">$splunkEvent</span> = [
<span style="color:#86efac;">'time'</span> => <span style="color:#f1fa8c;">$payload</span>[<span style="color:#86efac;">'created'</span>],
<span style="color:#86efac;">'host'</span> => <span style="color:#86efac;">'nis2-agile'</span>,
<span style="color:#86efac;">'source'</span> => <span style="color:#86efac;">'nis2-agile-webhook'</span>,
<span style="color:#86efac;">'sourcetype'</span> => <span style="color:#86efac;">'nis2:event'</span>,
<span style="color:#86efac;">'index'</span> => <span style="color:#86efac;">'nis2_compliance'</span>,
<span style="color:#86efac;">'event'</span> => [
<span style="color:#86efac;">'event_type'</span> => <span style="color:#f1fa8c;">$payload</span>[<span style="color:#86efac;">'event'</span>],
<span style="color:#86efac;">'event_id'</span> => <span style="color:#f1fa8c;">$payload</span>[<span style="color:#86efac;">'id'</span>],
<span style="color:#86efac;">'org_id'</span> => <span style="color:#f1fa8c;">$payload</span>[<span style="color:#86efac;">'org_id'</span>],
<span style="color:#86efac;">'data'</span> => <span style="color:#f1fa8c;">$payload</span>[<span style="color:#86efac;">'data'</span>],
<span style="color:#86efac;">'api_version'</span> => <span style="color:#f1fa8c;">$payload</span>[<span style="color:#86efac;">'api_version'</span>],
],
];
<span style="color:#7dd3fc;">// 3. Forward a Splunk HEC</span>
<span style="color:#f1fa8c;">$ch</span> = curl_init(<span style="color:#f1fa8c;">$splunkHec</span>);
curl_setopt_array(<span style="color:#f1fa8c;">$ch</span>, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(<span style="color:#f1fa8c;">$splunkEvent</span>),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
<span style="color:#86efac;">'Authorization: Splunk '</span> . <span style="color:#f1fa8c;">$splunkToken</span>,
<span style="color:#86efac;">'Content-Type: application/json'</span>,
],
]);
<span style="color:#f1fa8c;">$result</span> = curl_exec(<span style="color:#f1fa8c;">$ch</span>);
curl_close(<span style="color:#f1fa8c;">$ch</span>);
http_response_code(200);</pre>
</div>
<div class="section">
<h2>Elastic — Logstash Pipeline</h2>
<pre><span style="color:#7dd3fc;"># logstash/pipelines/nis2.conf</span>
input {
http {
port => 8181
codec => json
<span style="color:#7dd3fc;"># Aggiungi filtro HMAC-SHA256 con plugin custom</span>
}
}
filter {
mutate {
add_field => { "[@metadata][index]" => "nis2-compliance-%{+YYYY.MM}" }
}
date {
match => [ "[created]", "UNIX" ]
target => "@timestamp"
}
}
output {
elasticsearch {
hosts => ["https://elasticsearch:9200"]
index => "%{[@metadata][index]}"
}
}</pre>
</div>
<div class="section">
<h2>Microsoft Sentinel — Logic App</h2>
<pre><span style="color:#7dd3fc;">// Azure Logic App — trigger HTTP + azione Send to Log Analytics</span>
{
"triggers": {
"When_a_HTTP_request_is_received": {
"type": "Request",
"kind": "Http",
"inputs": { "schema": {} }
}
},
"actions": {
"Send_Data_to_Log_Analytics": {
"type": "ApiConnection",
"inputs": {
"body": "@{triggerBody()}",
"headers": { "Log-Type": "NIS2AgileEvent" },
"host": { "connection": { "name": "@parameters('$connections')['azureloganalyticsdatacollector']" } },
"method": "post",
"path": "/api/logs"
}
}
}
}</pre>
</div>
<div class="info-box info-purple">
<strong>Art.23 NIS2 + SIEM:</strong> Configurare alert SIEM su <code>incident.significant</code> e <code>incident.deadline_warning</code> permette di automatizzare il tracking delle scadenze 24h/72h/30d direttamente nel SOC. Il team può così gestire incidenti NIS2 senza uscire dal workflow SIEM.
</div>
</div>
</body>
</html>