[SEC+UX] Hardening sicurezza + miglioramenti UX pre-audit

SICUREZZA:
- index.php: rimosso CORS wildcard in debug mode (solo origini autorizzate)
- AuthController: getClientIP() con X-Forwarded-For sicuro (proxy-aware)
- AuthController: refresh token con SELECT FOR UPDATE in transazione atomica
- AIService: anonimizzazione dati org nei prompt Anthropic API (no nome/fatturato)

UX AUDIT-READY:
- dashboard.html: gauge rinominato 'Avanzamento implementazione misure Art.21'
- incidents.html: decision tree Art.23 con 5 criteri per 'Is Significant?'
- policies.html: banner warning obbligatorio su bozze generate da AI
- risks.html: tooltip dettagliati scala Likelihood/Impact (ISO 27005)
- assessment.html: progress bar % completamento risposta domande

DB:
- migration 006: indici performance + audit_log immutabile (trigger) + soft delete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
DevEnv nis2-agile
2026-02-20 12:01:33 +01:00
co-authored by Claude Sonnet 4.6
parent 0e78ec24c1
commit 782389849f
9 changed files with 282 additions and 39 deletions
+63
View File
@@ -519,6 +519,37 @@
<label class="form-label">Data e ora rilevamento <span class="required">*</span></label>
<input type="datetime-local" class="form-input" id="inc-detected-at" value="${dtLocal}">
</div>
<!-- Decision tree Art.23 NIS2 - significativita' incidente -->
<div style="background:var(--gray-50); border:1px solid var(--gray-200); border-radius:var(--border-radius); padding:14px; margin-bottom:16px;">
<div style="font-size:0.8rem; font-weight:700; color:var(--gray-700); margin-bottom:10px; display:flex; align-items:center; gap:6px;">
<svg viewBox="0 0 20 20" fill="currentColor" width="16" height="16" style="color:var(--primary);"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/></svg>
Criteri Art. 23 NIS2 — Incidente Significativo
</div>
<p style="font-size:0.75rem; color:var(--gray-500); margin-bottom:10px;">Un incidente e' significativo se soddisfa almeno uno dei criteri seguenti (Considerando 101 NIS2 / D.Lgs. 138/2024 art. 25):</p>
<div style="display:grid; gap:6px;">
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
<input type="checkbox" id="crit-users" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
<span>Ha causato o puo' causare interruzione grave dei servizi per <strong>&ge;500 utenti</strong></span>
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
<input type="checkbox" id="crit-duration" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
<span>Durata dell'interruzione superiore a <strong>4 ore</strong></span>
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
<input type="checkbox" id="crit-crossborder" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
<span>Impatto su altri Stati Membri UE (impatto transfrontaliero)</span>
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
<input type="checkbox" id="crit-attack" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
<span>E' un attacco cyber o data breach con dati personali coinvolti</span>
</label>
<label style="display:flex; align-items:center; gap:8px; font-size:0.8rem; cursor:pointer;">
<input type="checkbox" id="crit-financial" onchange="evalSignificance()" style="accent-color:var(--primary); width:16px; height:16px;">
<span>Perdita finanziaria stimata superiore a <strong>€100.000</strong></span>
</label>
</div>
<div id="significance-result" style="margin-top:10px; padding:8px 12px; border-radius:6px; font-size:0.8rem; font-weight:600; display:none;"></div>
</div>
<div class="form-group">
<label class="form-check-inline">
<input type="checkbox" id="inc-significant">
@@ -1142,6 +1173,38 @@
}
}
// ── Art.23 Significance Evaluator ────────────────────────────
function evalSignificance() {
const criteria = [
document.getElementById('crit-users'),
document.getElementById('crit-duration'),
document.getElementById('crit-crossborder'),
document.getElementById('crit-attack'),
document.getElementById('crit-financial'),
].filter(Boolean);
const checkedCount = criteria.filter(c => c.checked).length;
const resultDiv = document.getElementById('significance-result');
const sigCheckbox = document.getElementById('inc-significant');
if (!resultDiv) return;
resultDiv.style.display = 'block';
if (checkedCount >= 1) {
resultDiv.style.background = '#fef2f2';
resultDiv.style.border = '1px solid #fca5a5';
resultDiv.style.color = 'var(--danger)';
resultDiv.innerHTML = '&#9888; ' + checkedCount + ' criteri soddisfatti — l'incidente e' probabilmente <strong>SIGNIFICATIVO</strong>. Attivare le notifiche Art. 23 (24h/72h/30gg).';
if (sigCheckbox) sigCheckbox.checked = true;
} else {
resultDiv.style.background = '#f0fdf4';
resultDiv.style.border = '1px solid #bbf7d0';
resultDiv.style.color = 'var(--secondary)';
resultDiv.innerHTML = '&#10003; Nessun criterio soddisfatto — l'incidente appare <strong>NON significativo</strong> ai fini Art. 23. Verificare manualmente prima di confermare.';
if (sigCheckbox) sigCheckbox.checked = false;
}
}
// ── Navigation ───────────────────────────────────────────────
function backToList() {
document.getElementById('view-detail').classList.add('hidden');