La password non lascia il browser. Hashare una password su un servizio online generico è un controsenso di sicurezza: stai inviando una credenziale in chiaro a un terzo. Qui il calcolo avviene interamente nel tab, in JavaScript e WebAssembly, senza alcuna richiesta di rete. Puoi verificarlo aprendo il pannello Network degli strumenti per sviluppatori: digiti una password, generi l'hash, e non parte nessuna richiesta HTTP. Una volta caricata, la pagina funziona anche offline.
Le password non vanno hashate con funzioni veloci. MD5, SHA-1, SHA-256 sono progettate per essere velocissime: una GPU moderna ne calcola miliardi al secondo. Applicata a una password, questa velocità lavora a favore dell'attaccante che ha rubato il database: con un dizionario e una scheda grafica prova miliardi di candidati al secondo. In più, senza salt, hash uguali rivelano password uguali e permettono l'uso di rainbow table precalcolate. bcrypt e Argon2 fanno l'opposto: sono deliberatamente lente e regolabili, così che ogni tentativo costi tempo (e per Argon2 anche memoria) all'attaccante.
Il salt è già dentro l'hash. Un hash bcrypt come $2y$12$R9h/cIPz0gi.URNNX3kh2O... è un pacchetto autoconsistente: $2y$ è la versione, 12 è il cost factor, i 22 caratteri successivi sono il salt (128 bit casuali) e il resto è il digest vero e proprio (184 bit). Per Argon2id l'output $argon2id$v=19$m=19456,t=2,p=1$salt$hash incorpora versione, parametri di memoria/tempo/parallelismo, salt e digest. Non devi memorizzare il salt in una colonna separata: verificare significa rileggere quei parametri dall'hash e ricalcolare. È il motivo per cui password_verify() vuole solo password e hash, e nient'altro.
bcrypt o Argon2id: quale. Per un nuovo progetto la raccomandazione 2026 è Argon2id, che è memory-hard: costringe l'attaccante a usare molta RAM per ogni tentativo, neutralizzando il vantaggio di GPU e ASIC che invece macinano bene bcrypt. bcrypt resta perfettamente valido, è ovunque (PHP, Laravel, Spring, Node) e non ha dipendenze particolari: il suo limite storico è che tronca la password a 72 byte e non è memory-hard. Se il tuo stack supporta Argon2id, preferiscilo; se devi restare compatibile con un ecosistema che parla bcrypt, un cost factor adeguato è ancora una scelta solida.