Vai al contenuto
2FAAuth.Work
Lingua: Italiano
10 min di lettura Di 2faauth.work Politica editoriale

Come funziona TOTP: la matematica dietro il codice a 6 cifre

Una spiegazione in parole semplici di come vengono generati i codici password monouso basati sul tempo, dal segreto condiviso alle sei cifre che digiti.

Che cos'è davvero un codice TOTP

Apri la tua app di autenticazione e vedrai un numero a 6 cifre che conta alla rovescia i suoi 30 secondi di vita. Quel numero è un codice TOTP: una password monouso basata sul tempo, standardizzata in RFC 6238 come estensione del precedente schema basato su HMAC, HOTP.

L'idea chiave: il codice non è una password. È la prova che possiedi un segreto condiviso — un valore installato sul tuo dispositivo quando hai configurato per la prima volta il 2FA. Poiché il codice è derivato da quel segreto più l'ora corrente, cambia ogni 30 secondi ed è inutile per chiunque lo intraveda dopo che l'hai digitato.

Nulla viaggia perché tutto questo funzioni. Nessun SMS, nessuna connessione al server di login, nessuna rete. La tua app e il server eseguono lo stesso calcolo in modo indipendente, sui rispettivi orologi. Stessi input, stessa matematica, stesso codice — questo è tutto il trucco.

La differenza con HOTP sta proprio nel contatore: HOTP usa un contatore che avanza a ogni uso, TOTP lo sostituisce con il tempo. Nessuna sincronizzazione di contatori tra app e server, quindi nessun rischio di desincronizzazione se salti un codice o ne generi uno senza usarlo. Il costo è un altro requisito: gli orologi devono essere abbastanza allineati. Se il server accetta un piccolo margine di errore — tipicamente un passo avanti o indietro — uno sfasamento di pochi secondi non blocca il login. Per questo la raccomandazione pratica è semplice: lascia attiva la sincronizzazione automatica dell'ora sul telefono. Un orologio manuale sbagliato di qualche minuto è la causa più comune di codici "sempre errati".

Il Segreto Condiviso: Dove Tutto Inizia

Quando attivi l'autenticazione a due fattori su un account, il server genera una chiave segreta casuale — in genere 20 byte di casualità crittografica. Questa singola stringa di caratteri è la radice di tutto ciò che segue.

Il te la consegna una sola volta, di solito come codice QR. Ciò che sembra un pattern di pixel è in realtà solo testo codificato: il segreto stesso, scritto in Base32 (lettere A–Z e cifre 2–7), più il nome dell'account e l'issuer. La tua app di autenticazione lo scansiona, lo decodifica e memorizza il segreto in locale.

Il Base32 esiste perché un segreto binario deve essere trascritto a mano in caso di emergenza: 32 caratteri, tutti maiuscoli, senza 0, 1, 8 o 9. Così un O si confonde solo con un O, mai con uno zero. Se devi digitare il segreto manualmente, ogni errore di battitura produce codici sempre sbagliati: il rimedio è cancellare l'account dall'app e rifare la scansione da capo.

Da quel momento, esistono due copie dello stesso segreto: una sul server, una nella tua app. Nessuna delle due viene mai più inviata attraverso la rete. Ogni codice futuro deriva da questo valore condiviso — ed è proprio per questo che proteggerlo è importante.

Uno screenshot di quel codice QR è una copia permanente della tua chiave. Chiunque lo veda può generare codici validi per sempre. Scansionalo, poi eliminalo.

Il Passo Temporale: Un Contatore in Movimento

TOTP non usa mai l'orologio raw direttamente. Invece, sia la tua app che il server prendono il timestamp Unix corrente (secondi dal 1970) e lo dividono per 30, scartando il resto:

counter = floor(unix_time / 30)

Il risultato è un semplice intero che avanza di uno ogni 30 secondi. Al momento della scrittura, quel contatore è un numero enorme — ma all'app interessa solo che entrambe le parti calcolino lo stesso valore. Stesso contatore più stesso segreto significa stesso codice.

Esempio concreto: alle 12:00:00 il timestamp è un multiplo di 30, quindi il contatore cambia esattamente in quel momento. Un codice generato alle 11:59:58 resta valido per soli 2 secondi; uno generato alle 12:00:01 per 29. Per questo l'app mostra spesso una barra di progresso: ti dice quanto tempo resta prima che il codice diventi inutilizzabile.

Perché la Deriva dell'Orologio Rompa i Codici

L'intero schema si basa sull'accordo. Se l'orologio del tuo telefono è sfasato di 40 secondi, calcoli il contatore N mentre il server è già su N+1 — codici diversi, errore "codice non valido", anche se l'hai digitato perfettamente. Errore classico: cambiare telefono e ripristinare un backup senza controllare la data automatica; i primi login TOTP falliscono tutti, e si colpisce la colpa del codice sbagliato.

I server sanno che gli orologi derivano, quindi la maggior parte accetta il codice del passo temporale precedente o successivo come finestra di tolleranza. Oltre a ciò, risincronizza l'orologio del dispositivo (impostalo su automatico). Se l'errore persiste con l'orologio corretto, il problema è quasi sempre il segreto condiviso: rifai la scansione del QR code invece di continuare a riprovare.

HMAC: mescolare il segreto e il contatore

Al cuore di ogni codice TOTP c'è una singola funzione: HMAC-SHA1. HMAC sta per Hash-based Message Authentication Code, e il suo compito qui è semplice — fondere due input in un unico output imprevedibile.

I due input:

  • Il segreto condiviso — la chiave, nota solo al tuo telefono e al server
  • Il contatore temporale — il numero che cambia ogni 30 secondi

Pensa a HMAC come a un hash con chiave. Un hash semplice mescola i dati allo stesso modo ogni volta. HMAC li mescola in modo diverso a seconda della chiave. Dagli lo stesso segreto con contatore 48291 e ottieni sempre lo stesso risultato di 20 byte. Cambia il contatore di uno, e l'output si sposta in qualcosa che sembra completamente non correlato.

Questa deterministica ha una conseguenza pratica: telefono e server non devono scambiarsi nulla in tempo reale. Calcolano lo stesso HMAC indipendentemente, e i risultati coincidono. Ecco perché TOTP funziona anche in aereo, senza rete.

Fondamentale: il processo scorre in una sola direzione. Vedere milioni di output non dice a un attaccante nulla di utilizzabile sul segreto — è questa la proprietà che rende sicuro l'intero schema. Il segreto non viaggia mai dopo la configurazione iniziale: solo i codici a 6 cifre, inutili da soli, passano per la rete. Se un codice viene intercettato, scade da solo dopo 30 secondi e non rivela il segreto che l'ha generato.

Troncamento: da 20 byte a 6 cifre

HMAC-SHA-1 produce 20 byte — molto più di quanto un display possa ragionevolmente mostrare. TOTP li comprime con il troncamento dinamico:

  1. Prendi l'ultimo nibble (i 4 bit meno significativi) dell'output HMAC. Questo dà un numero da 0 a 15.
  2. Usalo come offset: prendi i 4 byte che iniziano in quella posizione dell'output.
  3. Maschera il bit più significativo di quei 4 byte, lasciando un intero a 31 bit.

La maschera serve a evitare che l'intero risulti negativo in linguaggi con interi con segno: azzerando il bit più alto, il valore resta sempre positivo e la matematica successiva è prevedibile su qualsiasi piattaforma.

Quell'intero è ancora troppo grande da mostrare, quindi viene ridotto modulo 1.000.000. Il resto — un valore da 0 a 999.999 — diventa il codice, con riempimento di zeri fino a 6 cifre. Un resto di 4.207 viene visualizzato come 004207: senza il riempimento, un'app o un utente potrebbero scambiarlo per un codice a 4 cifre e l'inserimento fallirebbe.

Si chiama dinamico perché l'offset deriva dai dati stessi: ogni codice campiona una porzione diversa dell'output HMAC, senza bisogno di coordinate esterne.

Alcuni servizi usano codici a 7 o 8 cifre, riducendo invece modulo 10.000.000 o 100.000.000 — stessa matematica, spazio di codici più ampio, più difficile da indovinare a colpo d'occhio o a tentativi ripetuti.

Perché il Codice è Sicuro da Digitare

Un codice a 6 cifre offre un milione di valori possibili — modesto sulla carta. Ciò che lo rende efficace è che hai solo pochi tentativi a disposizione. I server limitano la frequenza dei tentativi di accesso e rifiutano i fallimenti ripetuti, quindi un attaccante non può provare le combinazioni in sequenza. Nella pratica, dopo tre a cinque errori consecutivi l'account viene temporaneamente bloccato o sottoposto a una verifica aggiuntiva. A un milione di possibilità e tre tentativi per finestra, la probabilità di indovinare resta trascurabile. Il rate limiting, non la lunghezza del codice, è la vera difesa.

Ogni codice è inoltre di breve durata. È legato a una finestra di 30 secondi e accettato solo brevemente attorno ad essa, quindi un codice rubato scade prima di poter essere riutilizzato. Un attaccante che ottiene il codice via phishing deve usarlo entro quei secondi, spesso prima ancora di riceverlo.

Infine, vedere un codice non rivela nulla sul futuro. Il codice è l'output di un calcolo HMAC che utilizza la tua chiave segreta. HMAC è una funzione a senso unico: dato l'output, non c'è modo di ricostruire l'input. Un attaccante che intravede il codice di oggi non può ricavare il segreto, né prevedere il codice di domani — perché non conosce il valore di accoppiamento del contatore sottostante. È come vedere il risultato di un dado: il numero osservato non dice nulla sui lanci successivi.

Domande comuni e casi limite

Perché i codici non funzionano

La causa più comune è la deriva dell'orologio. L'orologio del telefono e quello del server devono rimanere entro la finestra consentita, quindi un telefono con l'ora sbagliata genera codici errati. Soluzione: attiva la sincronizzazione automatica dell'ora. Se il tuo servizio offre un "riallineamento" del token, usalo: registra l'orologio del dispositivo e rifiuta i codici vecchi di pochi minuti.

Anche un segreto errato fallisce silenziosamente—questo accade di solito quando il codice QR è stato scansionato nella configurazione di un account diverso. Verifica che l'app mostri il nome utente e il servizio corretti. Infine, i codici QR possono scadere: molti servizi invalidano il codice di registrazione dopo un breve periodo o dopo aver superato la schermata, quindi un vecchio screenshot non funzionerà. Se il codice viene rifiutato subito dopo la scansione, ricomincia la configurazione da zero con un QR nuovo.

Un codice può essere riutilizzato?

Sì, tecnicamente—ma la maggior parte dei server rifiuta un codice già accettato nel time step corrente. Questo blocca gli attaccanti che intravedono un codice e lo ripetono pochi secondi dopo. Alcuni server accettano anche il time step precedente o successivo, per tollerare piccoli ritardi di rete.

Se perdi il dispositivo

Il segreto condiviso risiede solo sul tuo dispositivo, quindi perderlo significa perdere l'accesso—a meno che tu non abbia salvato i codici di recupero durante la configurazione del 2FA. Conservali offline, ad esempio stampati in un luogo sicuro: un file nel cloud sincronizzato vanificherebbe la protezione. Ognuno in genere funziona una sola volta. Se li esaurisci, rigenerane di nuovi dalle impostazioni di sicurezza dell'account.

Mettere Tutto Insieme: Il Flusso Completo

Tutto si riduce a una sola pipeline: segreto condiviso → contatore temporale → HMAC → troncamento → 6 cifre.

Un ciclo di 30 secondi, dall'inizio alla fine:

  • Durante la configurazione, scansioni un codice QR. La tua app memorizza il segreto condiviso. Se scansioni di nuovo lo stesso QR in un'altra app, entrambe genereranno gli stessi codici: utile come backup, rischioso se il QR resta salvato in uno screenshot.
  • Alle 12:04:30, l'app calcola il time step corrente (circa 24.000 se si conta dall'epoca Unix a blocchi di 30 secondi). Il calcolo è solo una divisione intera: floor(secondi / 30).
  • HMAC-SHA1 mescola il segreto con quel contatore, producendo 20 byte.
  • Il troncamento sceglie 4 di quei byte, li converte in un numero e tiene le ultime 6 cifre: ad esempio, 482913.
  • Lo digiti. Il server, che possiede lo stesso segreto, esegue il calcolo identico—consentendo uno o due step di scarto per differenze di orologio—e i codici corrispondono. Se sbagli l'ultimo secondo della finestra, non serve panico: il server verifica anche il time step precedente.

Due abitudini proteggono l'intera catena: tratta il codice QR come una password—non fotografarlo, non inviarlo in chat, cancellalo subito dopo l'uso—e tieni l'orologio del dispositivo impostato su automatico. Un orologio errato di pochi minuti è la causa più comune di codici rifiutati, perché il time step calcolato non corrisponde più a quello del server. Con quelle due cose a posto, la matematica si gestisce da sola.

Condividi questa guida

9 min di lettura

La storia del 2FA: dai token hardware alle passkey

Come l'autenticazione a due fattori si è evoluta dai token hardware da clip e dai codici SMS fino alle odierne passkey resistenti al phishing — e il perché di ogni passaggio.

Leggi di più