Esiste una categoria di attacchi sorprendente: non sfrutta un bug nel codice, ma il tempo che il sistema impiega a rispondere. Misurando i millisecondi, un attaccante può estrarre un segreto. Si chiamano timing attack, e si neutralizzano con un confronto "a tempo costante".

Cos'è un timing attack

Immagina che il sistema confronti un token carattere per carattere e si fermi al primo che non combacia. Più caratteri iniziali sono corretti, più tempo impiega. Misurando quei tempi, l'attaccante indovina il segreto un pezzo alla volta.

Perché il confronto "normale" è vulnerabile

Il confronto ingenuo (che si interrompe appena trova una differenza) "perde tempo" in modo misurabile e correlato al segreto. È proprio questa correlazione a essere sfruttabile.

Il confronto a tempo costante

La soluzione è confrontare i valori in un tempo che non dipende da quanto combaciano. In Node.js esiste una funzione apposita:

const crypto = require('crypto');
crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));

Il tempo è sempre lo stesso, quindi non rivela nulla.

Dove si applica

Ovunque si confronti un segreto: token di sessione, firme, chiavi API, codici di verifica. È un accorgimento piccolo ma che distingue il software fatto con cura.

Il confronto costante da solo non basta

Due dettagli operativi: timingSafeEqual richiede buffer della stessa lunghezza e solleva un'eccezione altrimenti, quindi si confrontano valori a lunghezza fissa (per esempio l'hash del token, non il token grezzo). E il tempo può rientrare dalla finestra: se un token valido innesca una query al database e uno inesistente no, la differenza torna misurabile a livello di richiesta, indipendentemente da come è stato fatto il confronto.

Collegato: hash delle password e rate limiting.