[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
+26 -12
View File
@@ -442,7 +442,25 @@
const TREATMENT_STATUS_LABELS = {
planned: 'Pianificato', in_progress: 'In Corso', completed: 'Completato', cancelled: 'Annullato'
};
// Scala Likelihood (probabilità annua)
const LIKELIHOOD_LABELS = ['', 'Molto Basso', 'Basso', 'Medio', 'Alto', 'Molto Alto'];
const LIKELIHOOD_DETAILS = [
'',
'1 - Remota: <1% probabilità annua (evento eccezionale)',
'2 - Improbabile: 1-10% (evento raro ma documentato nel settore)',
'3 - Possibile: 10-30% (può verificarsi nel corso dell'attività)',
'4 - Probabile: 30-70% (ci si aspetta che avvenga almeno una volta l'anno)',
'5 - Quasi Certa: >70% (si verificherà con elevata probabilità)',
];
// Scala Impact (danno economico / utenti impattati)
const IMPACT_DETAILS = [
'',
'1 - Minimo: <€10k danno, <100 utenti, servizio ripristinato in <1h',
'2 - Basso: €10k-50k, 100-500 utenti, ripristino <8h',
'3 - Significativo: €50k-500k, 500-5000 utenti, ripristino <24h',
'4 - Grave: €500k-10M, 5000-50000 utenti, ripristino <7 giorni',
'5 - Catastrofico: >€10M, >50000 utenti, servizi critici nazionali impattati',
];
// ── State ────────────────────────────────────────────────────
let currentView = 'table';
@@ -878,22 +896,16 @@
<div class="form-row">
<div class="form-group">
<label class="form-label">Probabilita': <span id="likelihood-label">${LIKELIHOOD_LABELS[likelihood]}</span></label>
<label class="form-label">Probabilita' <span style="color:var(--gray-400); font-size:0.75rem; font-weight:400;">(frequenza stimata annua)</span></label>
<div class="range-value-display" id="likelihood-value">${likelihood}</div>
<input type="range" class="form-range" id="risk-likelihood" min="1" max="5" value="${likelihood}" oninput="updateRiskScore()">
<div class="form-range-labels">
<span>1 - Molto Basso</span>
<span>5 - Molto Alto</span>
</div>
<div style="font-size:0.75rem; color:var(--gray-500); margin-top:4px; padding:6px 8px; background:var(--gray-50); border-radius:4px;" id="likelihood-detail">${LIKELIHOOD_DETAILS[likelihood]}</div>
</div>
<div class="form-group">
<label class="form-label">Impatto: <span id="impact-label">${LIKELIHOOD_LABELS[impact]}</span></label>
<label class="form-label">Impatto <span style="color:var(--gray-400); font-size:0.75rem; font-weight:400;">(danno economico / utenti)</span></label>
<div class="range-value-display" id="impact-value">${impact}</div>
<input type="range" class="form-range" id="risk-impact" min="1" max="5" value="${impact}" oninput="updateRiskScore()">
<div class="form-range-labels">
<span>1 - Molto Basso</span>
<span>5 - Molto Alto</span>
</div>
<div style="font-size:0.75rem; color:var(--gray-500); margin-top:4px; padding:6px 8px; background:var(--gray-50); border-radius:4px;" id="impact-detail">${IMPACT_DETAILS[impact]}</div>
</div>
</div>
@@ -934,8 +946,10 @@
document.getElementById('likelihood-value').textContent = l;
document.getElementById('impact-value').textContent = i;
document.getElementById('likelihood-label').textContent = LIKELIHOOD_LABELS[l];
document.getElementById('impact-label').textContent = LIKELIHOOD_LABELS[i];
const lDetail = document.getElementById('likelihood-detail');
const iDetail = document.getElementById('impact-detail');
if (lDetail) lDetail.textContent = LIKELIHOOD_DETAILS[l];
if (iDetail) iDetail.textContent = IMPACT_DETAILS[i];
document.getElementById('score-preview-value').textContent = score;
document.getElementById('score-preview-value').style.color = getScoreColorForRisk(score);
}