modulo 18 di 24 / Ore 41-60
Moduli 17-24 / Checkpoint 60 ore
Input non fidati: cosa può arrivare dall'utente
Riconoscere cosa può arrivare di sbagliato dall'utente nel Registro del laboratorio, dove va validato e come distinguere sanitizzazione, validazione e normalizzazione.
Input non fidati: cosa può arrivare dall’utente
Questa lezione appartiene al Modulo 18 — Sicurezza di base.
Perché l’input non è mai affidabile
Ogni volta che un utente compila un form, può inviare dati che il sistema non si aspetta. Non per malice necessariamente — per errore, per copia-incolla, per browser che si comportano in modo diverso.
Nel Registro del laboratorio, i campi che accettano input dell’utente sono:
- Nome strumento
- Categoria
- Motivo del guasto (testo libero)
- ID strumento (da form di ricerca o prestito)
Ognuno di questi può contenere qualcosa di inaspettato.
Cosa può arrivare — esempi concreti
| Campo | Input atteso | Cosa può arrivare |
|---|---|---|
| Nome strumento | "Trapano elettrico" |
"", " ", "<script>alert(1)</script>", stringa da 5000 caratteri |
| Categoria | "Elettrico" |
"", valore non nella lista, "undefined" (se JS ha un bug) |
| Motivo guasto | Frase breve | Stringa vuota, testo di 10.000 caratteri, testo con nomi di persone |
| ID strumento | "str-042" |
"", null, ID inesistente, caratteri speciali |
Tre operazioni distinte sull’input
Spesso si confondono tre operazioni diverse. È utile distinguerle:
1. Normalizzazione — porta l’input in una forma standard, senza rifiutarlo:
function normalizzaTesto(testo) {
if (typeof testo !== "string") return "";
return testo.trim(); // rimuove spazi iniziali e finali
}
2. Validazione — verifica che l’input rispetti i vincoli, altrimenti lancia un errore:
function validaNome(nome) {
if (nome.length < 2) throw new Error("NOME_TROPPO_CORTO");
if (nome.length > 80) throw new Error("NOME_TROPPO_LUNGO");
}
3. Sanitizzazione — rimuove o neutralizza caratteri potenzialmente pericolosi:
// Nel contesto del Registro (solo localStorage, nessun server)
// XSS non è un rischio reale — ma è buona abitudine non salvare HTML grezzo
function sanitizzaTesto(testo) {
return testo.replace(/</g, "<").replace(/>/g, ">");
}
Nel Registro scolastico, la sanitizzazione contro XSS è a bassa priorità (localStorage non esegue script). La normalizzazione e la validazione sono invece indispensabili.
Dove va fatto ogni controllo
Presentation → normalizzazione (trim), feedback immediato al form
Application → validazione definitiva prima di passare al dominio
Domain → presuppone input già valido (non valida, usa)
Infrastructure → nessun input raw — riceve solo dati già validati
La regola pratica: normalizza il prima possibile, valida prima di creare il comando, non lasciare che dati grezzi raggiungano il dominio.
Esempio completo — registrazione strumento
// presentation/formRegistraStrumento.js
document.getElementById("form-strumento").addEventListener("submit", async (e) => {
e.preventDefault();
// 1. Normalizzazione — prima di tutto
const nome = normalizzaTesto(document.getElementById("nome").value);
const categoria = normalizzaTesto(document.getElementById("categoria").value);
// 2. Validazione rapida nella UI — feedback immediato
if (nome.length < 2) {
mostraErroreCampo("nome", "Il nome deve avere almeno 2 caratteri.");
return;
}
if (!categoria) {
mostraErroreCampo("categoria", "Seleziona una categoria.");
return;
}
const comando = {
id: crypto.randomUUID(),
nome, // già normalizzato
categoria // già normalizzato
};
try {
// 3. Validazione definitiva nel caso d'uso
await registraStrumento(comando);
mostraSuccesso("Strumento registrato.");
} catch (errore) {
mostraMessaggio(traduciErrore(errore.message));
}
});
// application/registraStrumento.js
function creaRegistraStrumento({ archivioStrumenti }) {
return async function registraStrumento(comando) {
// Validazione difensiva — anche se la UI ha già validato
if (!comando.nome || comando.nome.length < 2) throw new Error("NOME_NON_VALIDO");
if (!comando.categoria) throw new Error("CATEGORIA_MANCANTE");
if (!comando.id) throw new Error("ID_MANCANTE");
const strumento = creaStrumento(comando); // il dominio presuppone dati validi
await archivioStrumenti.salva(strumento);
};
}
Input da campo di ricerca
Il campo di ricerca è un caso particolare: non è obbligatorio e può contenere qualsiasi testo. La normalizzazione è sufficiente — la validazione sarebbe eccessiva.
// Ricerca: normalizza ma non rifiutare l'input vuoto
function normalizzaQuery(query) {
if (typeof query !== "string") return "";
return query.trim().toLowerCase();
}
// Se la query è vuota, restituisce tutti gli strumenti
function cercaStrumenti(archivio, query) {
const q = normalizzaQuery(query);
if (q.length === 0) return archivio.leggiTutti();
return archivio.leggiTutti().filter(s =>
s.nome.toLowerCase().includes(q) ||
s.categoria.toLowerCase().includes(q)
);
}
Procedura guidata
- Elenca tutti i form del Registro che accettano input dell’utente.
- Per ogni campo: quale normalizzazione serve? Quale validazione?
- Aggiungi
normalizzaTestoovunque si legge uninput.value. - Aggiungi validazione nel caso d’uso prima di usare il dato.
- Verifica che il dominio non riceva mai una stringa vuota o
undefinednei campi obbligatori.
Attività in classe
## Input non fidati nel mio Registro
Form analizzato:
Campi con input utente:
Per ogni campo:
- Normalizzazione applicata:
- Validazione applicata:
- Cosa succede se il campo è vuoto:
Input che raggiungono il dominio senza validazione (da correggere):
Spiegazione guidata per studiare
Ogni campo form è un punto di ingresso nel sistema. L’utente può inserire qualsiasi cosa — non perché sia malevolo, ma perché i browser, i copia-incolla e gli errori di digitazione producono input inaspettati.
Il punto centrale è: normalizza all’ingresso, valida prima di usare, non fidarti di nessun valore raw. Questa catena — normalizzazione → validazione → uso — protegge il dominio da dati malformati.
La differenza tra normalizzazione e validazione è importante: normalizzare trasforma (.trim()), validare rifiuta (lancia un errore). Un campo vuoto dopo .trim() viene rifiutato dalla validazione — ma la normalizzazione non lo rifiuta, solo lo pulisce.
Passo per passo nel progetto
- Apri tutti i form del Registro.
- Ogni
input.valueviene letto direttamente nel comando? Aggiungi.trim(). - Il caso d’uso ha almeno un controllo
if (!campo || campo.length < N)per i campi obbligatori? - Prova a inviare il form con tutti i campi vuoti — cosa succede?
- Aggiungi la validazione mancante e verifica di nuovo.
Esempio da leggere lentamente
// Senza protezione — tutto può arrivare al dominio
const comando = {
nome: document.getElementById("nome").value, // può essere ""
categoria: document.getElementById("cat").value, // può essere ""
};
creaStrumento(comando); // il dominio riceve "" come nome — produce dati corrotti
// Con protezione — tre passi in sequenza
const nomeCrudo = document.getElementById("nome").value;
const nome = normalizzaTesto(nomeCrudo); // 1. normalizza
validaNome(nome); // 2. valida (lancia se non valido)
const comando = { id: crypto.randomUUID(), nome, categoria }; // 3. usa
creaStrumento(comando); // il dominio riceve dati già verificati
Prova di comprensione
- Qual è la differenza tra normalizzazione e validazione? Fai un esempio per ciascuna.
- Perché la validazione nella UI non è sufficiente da sola?
- Cosa succede nel tuo progetto se l’utente invia il form con il nome vuoto?
Errori da evitare
- usare
input.valuedirettamente nel comando senza.trim(); - fare la validazione solo nella UI — il caso d’uso deve difendersi da solo;
- confondere normalizzazione e validazione (non rifiutare in normalizzazione);
- validare nel dominio — il dominio deve presupporre dati già validi.
Prodotto da consegnare
Può essere:
- una funzione
normalizzaTestousata in tutti i form; - una funzione
validaComandoRegistraStrumentocon almeno tre controlli; - un test che verifica che il caso d’uso lanci
NOME_NON_VALIDOcon input vuoto.
Checklist di chiusura
- Ogni
input.valueviene normalizzato con.trim()prima dell’uso - Il caso d’uso valida i campi obbligatori prima di passarli al dominio
- Il dominio non riceve mai stringhe vuote nei campi obbligatori
- Il form mostra errori comprensibili per ogni campo non valido
- Ho verificato cosa succede inviando il form con tutti i campi vuoti
Domande per la revisione
- Hai trovato campi letti senza
.trim()? Quanti? - Il dominio ha mai ricevuto una stringa vuota durante i tuoi test?
- Qual è il campo più “pericoloso” del tuo Registro (quello più facile da lasciare vuoto per errore)?
Risultato atteso
Alla fine lo studente deve saper dire:
Nel mio Registro, i form che accettano input sono: [lista].
Per il campo [X] applico questa normalizzazione: [trim/lowercase/altro].
La validazione avviene in [UI / caso d'uso / entrambi].
Ho verificato il comportamento con input vuoto: [risultato].
Se questa spiegazione non è possibile, la lezione non è ancora davvero conclusa.