Note di Matteo


#security

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

A volte sorprende come le grandi aziende prendano così poco seriamente la sicurezza e che sia impossibile segnalare vulnerabilità:

Despite its vast wealth, Condé Nast lacks a security.txt file that explains how to report a vulnerability to them. Nowhere on its site did it plainly explain how to report a vulnerability to them.

Trying to help Condé Nast avoid compromise of what was described to me as a serious vulnerability risking more than 33 million users’ accounts, I reached out to people I know at WIRED. I also reached out to Condé Nast but received no replies from them.

(Condé Nast gets hacked)

#265 /
28 dicembre 2025
/
09:36
/ #security


Let's Encrypt compie 10 anni

A conspicuous part of Let’s Encrypt’s history is how thoroughly our vision of scalability through automation has succeeded.

In March 2016, we issued our one millionth certificate. Just two years later, in September 2018, we were issuing a million certificates every day. In 2020 we reached a billion total certificates issued and as of late 2025 we’re frequently issuing ten million certificates per day. We’re now on track to reach a billion active sites, probably sometime in the coming year.

(LE)

#227 /
14 dicembre 2025
/
10:54
/ #security#cloud


Vercel ha pagato 750mila dollari di bug bounty per 15 bypass WAF contro React2Shell durante il weekend.

#216 /
8 dicembre 2025
/
21:06
/ #security

HTTPS by default

In Chrome dall'ottobre 2026:

One year from now, with the release of Chrome 154 in October 2026, we will change the default settings of Chrome to enable “Always Use Secure Connections”. This means Chrome will ask for the user's permission before the first access to any public site without HTTPS.

#133 /
6 novembre 2025
/
21:07
/ #http#browser#security


Lavorare con Safari è una pena:

  • i cookie Secure non vanno su localhost perché Safari non supporta Secure Context come gli altri browser.
  • i sottodomini di localhost non funzionano fino a macOS 26, da cui starò alla larga per un po'.
  • nella scheda Storage -> Cookies non si vedono i cookie di terze parti o dei sottodomini??? come in tutti gli altri browser.
  • al momento non riesco a far funzionare un semplice cookie SameSite=Lax del tutto, su localhost con HTTPS. Nella risposta c'è, ma non lo salva. Con gli altri browser funziona.
  • ok, non sono l'unico. Rinuncio.
#82 /
18 ottobre 2025
/
10:08
/ #dev#security#browser

Defunte definitivamente quasi tutte le iniziative di Chrome per uccidere i cookie di terze parti (Privacy Sandbox), restano solo i cookie partizionati e poco altro:

CHIPS and FedCM, which improve cookie privacy and security and streamline identity flows respectively, have seen broad adoption, including support from other browsers. We'll continue to support those APIs and evaluate opportunities for future enhancements. We'll also maintain Private State Tokens and explore additional approaches to help developers reduce fraud and abuse.

After evaluating ecosystem feedback about their expected value and in light of their low levels of adoption, we've decided to retire the following Privacy Sandbox technologies: Attribution Reporting API (Chrome and Android), IP Protection, On-Device Personalization, Private Aggregation (including Shared Storage), Protected Audience (Chrome and Android), Protected App Signals, Related Website Sets (including requestStorageAccessFor and Related Website Partition), SelectURL, SDK Runtime and Topics (Chrome and Android). We will follow Chrome and Android processes for phasing out these technologies and share updates on our developer site.

#81 /
18 ottobre 2025
/
09:46
/ #dev#security#browser

Fineco scrive via email: "Attenzione alle frodi bancarie". Alla fine si specifica che il sito ufficiale è https://it.finecobank.com, ma il link non porta lì. Non è così che si costruisce un sistema di fiducia.

#77 /
16 ottobre 2025
/
22:43
/ #security

SameSite e protezione CSRF con Sec-Fetch-Site

Un po' di risorse sulle tecniche moderne per la protezione da CSRF:

#75 /
16 ottobre 2025
/
21:34
/ #dev#security#browser

TIL Argon2 per le password non è più sicuro di bcrypt come si pensa:

[...] Me (@jmgosney) and @Sc00bzT were both on the experts panel for the Password Hashing Competition, and both of us will tell you not to use Argon2 for password hashing. It is weaker than bcrypt at runtimes < 1000 ms.

Yep, we basically completely failed. We set out to identify The One True PHF and instead we selected yet another KDF. We also placed way too much emphasis on "memory hardness" when we should have been emphasizing "cache hardness."

@TerahashCorp

Bottom line, if you're already using argon2, you're totally fine. It's still a good PHF and much better than most everything out there. But if you aren't using argon2, bcrypt is a better choice.

@jmgosney

#69 /
14 ottobre 2025
/
21:07
/ #dev#security