Note di Matteo


Progetti

2FA for developers

Ho aggiunto il supporto all'autenticazione a due fattori su DMARCwise e ho fatto fatica a trovare informazioni su best practice attorno alla 2FA con OTP, per cui segno quello che ho scoperto qui.

Intanto, l'algoritmo si chiama Time-based One-Time Password (TOTP) e permette di generare un codice di N cifre ogni T secondi partendo da un secret. Non tutte le app "authenticator" supportano tutte le configurazioni, per cui la più comune è:

  • Codici di 6 cifre.
  • Intervallo di tempo T di 30 secondi.
  • Algoritmo HMAC-SHA1.

Il secret nella maggior parte dei casi è di 20 byte (160 bit) e viene codificato in Base32 (es. CVEBO7GKWLFDRBJRPPTOZ7I6VEPDIGIT). Va generato diverso per ogni utente.

Per la verifica del TOTP la RFC consiglia di usare una tolleranza (drift window) di +/- un intervallo di tempo T (quindi vale sia il codice precedente che quello successivo).

Il secret andrebbe cifrato prima di essere inserito nel database. Nel mio caso ho scelto AES-256 GCM. Nel db vanno quindi salvati il secret cifrato (Base64) più il nonce e il tag AES.

Per la validazione dei codici ho usato la libreria Otp.NET per .NET/C#. Per AES ho usato l'implementazione nativa di .NET.

Per la configurazione iniziale del secondo fattore, all'utente vanno forniti il secret e i vari parametri menzionati sopra (o anche no, dato che quelli indicati qui sopra sono di solito il default), oppure un QR code che contiene un URI con questo formato (inizialmente definito da Google ma ora standard de facto):

otpauth://totp/{label}:{accountName}?secret={secret}&issuer={issuer}";

I parametri vanno URL encoded. La prima etichetta viene mostrata nella UI dell'applicazione authenticator di turno (Google Authenticator, Ente Auth, ecc.) assieme al nome dell'account, mentre l'issuer dovrebbe essere a uso interno.

Il codice QR lo genero server-side in SVG con ZXing.QrCode e lo ritorno nella risposta JSON delle API. Probabilmente si può fare anche client-side, ma avevo già generato QR in C# in un altro progetto per cui ho riciclato il codice.

Per confermare l'abilitazione della 2FA l'utente deve inserire un primo codice TOTP generato dall'app authenticator. C'è la possibilità che l'utente abbandoni il processo a metà, per cui ci vuole un cleanup delle configurazioni che non sono ancora state abilitate dopo 24/48 ore.

Andrebbero poi generati e forniti dei codici di backup/recupero. Nel mio caso sono 10 codici di 8 caratteri presi dall'alfabeto ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (es. BVEZ-MMWP). Sono hashati con Argon2id, come le password, e salvati in una tabella del db. Di conseguenza nel momento della verifica del backup code bisogna verificarli tutti uno a uno per trovare se c'è un match, e poi segnare il codice individuato come già usato.

Come si implementa la verifica del secondo fattore in fase di login? Il login restituisce un token di tipo TwoFactorPending e il frontend fa redirect alla pagina di verifica. Questo token temporaneo permette di usare solo l'endpoint di verifica 2FA. Se il codice inserito dall'utente è corretto viene invalidato il token temporaneo (che ha comunque scadenza breve, es. 5 minuti) e ne viene creato uno nuovo "standard".

La disattivazione del secondo fattore deve richiedere la password dell'utente, mentre la rigenerazione dei codici di backup deve richiedere un codice TOTP valido (per verificare che l'utente sia effettivamente ancora in possesso del secondo fattore).

Bonus: il 95% del codice è stato scritto da Claude Code e dall'inizio alla fine ci abbiamo impiegato circa 3 giorni (progettazione, implementazione di 6 endpoint backend, integration test e tutta la UI con SvelteKit).

#291 /
16 gennaio 2026
/
20:25
/ #dev#security

certs.email

Ho pubblicato certs.email: un mini-servizio per essere notificati all'avvicinamento della scadenza dei certificati SSL/TLS dei propri domini.

È gratis e open source e in realtà mi serve prevalentemente per avere un dominio in più che invia email, per poter testare meglio DMARCwise.

#290 /
15 gennaio 2026
/
17:32
/ #dev#security

Nuovo mini progetto work in progress:

#262 /
24 dicembre 2025
/
15:28
/ #dev