import * as bcrypt from 'bcrypt';
import * as argon2 from 'argon2';
async function authenticateAndMigrate(
plainPassword: string,
user: { id: string; passwordHash: string }
): Promise<boolean> {
// Detectăm dacă e hash vechi de bcrypt (începe cu $2a$, $2b$ sau $2y$)
const isLegacyBcrypt = user.passwordHash.startsWith('$2');
if (isLegacyBcrypt) {
const isValid = await bcrypt.compare(plainPassword, user.passwordHash);
if (!isValid) return false;
// Parola e corectă: generăm hash-ul nou cu Argon2id
const newHash = await argon2.hash(plainPassword, {
type: argon2.argon2id,
memoryCost: 65536, // 64 MB RAM
timeCost: 3, // 3 iterații
parallelism: 1 // 1 thread
});
// Actualizăm silențios în DB
await db.user.update({
where: { id: user.id },
data: { passwordHash: newHash }
});
return true;
}
// Daca e deja Argon2id, doar verificăm
return await argon2.verify(user.passwordHash, plainPassword);
}Am refăcut recent modulul de auth la un proiect e-commerce cu vreo 35k useri și am descoperit că încă aveam în DB hash-uri bcrypt generate prin 2018 cu cost factor 10. În 2026, cu plăcile video din seria RTX 4000 sau servere dedicate de brute-force, un cost factor de 10 se sparge deranjant de repede. Dacă încă folosești bcrypt cu setările default din vechile tutoriale, e momentul să vorbim despre Argon2id și cum faci migrarea treptat, fără să pui aplicația în cap.
De ce bcrypt nu mai e de ajuns (dar nici o tragedie)
Bcrypt are două probleme mari în prezent. Prima e limita istorică de 72 de octeți pentru parolă — orice trece peste această lungime se taie tăcut. A doua e că algoritmul e strict CPU-bound. Plăcile video moderne au atât de multe nuclee încât pot rula atacuri paralele de tip dictionary pe bcrypt la viteze ametitoare.
Argon2id rezolvă problema asta fiind un algoritm memory-hard. Nu consumă doar procesor, ci obligă atacatorul să aloce o cantitate fixă de RAM pentru fiecare încercare. Un GPU are VRAM rapid, dar puțin per thread. Când Argon2id cere 64MB per hash, o placă video cu 24GB VRAM se blochează instant la câteva sute de încercări paralele în loc de milioane.
Trade-off-ul e evident: Argon2id mănâncă memorie reală pe serverul tău. Dacă ai un container de 512MB RAM pe Hetzner și prinzi un val de 100 de login-uri simultane, riști un OOM (Out Of Memory) rapid dacă n-ai calibrat parametrii.
Ce parametri folosim concret azi
Dacă rămâi totuși pe bcrypt din motive de compatibilitate legacy, urcă cost factor-ul la 12 sau 13. O durată acceptabilă pentru hashing pe server e în jur de 200-300ms per request de login. Sub 100ms e prea ușor de spart, iar peste 500ms începe să deranjeze userul și îți blochează thread-ul Node.js dacă folosești varianta sincronă.
Pentru Argon2id, un set solid de parametri pentru producție arată așa:
- Memory cost: 65536 KB (64 MB)
- Time cost (iterations): 3
- Parallelism: 1 sau 2 (în funcție de câte nuclee ai per container/pod)
La mine în teste pe un VPS modest cu 2 vCPU, diferența se vede clar: bcrypt cu cost 12 scoate ~280ms, iar Argon2id (64MB, t=3, p=1) scoate ~210ms, oferind o protecție la atacuri hardware net superioară la același timp de așteptare.
Stratagema de migrare: Lazy Re-hashing
Nu ai cum să convertești toată baza de date peste noapte într-un script de migrare. N-ai parolele în clar (sper!) ca să le poți re-hashea direct cu Argon2. Soluția pe care am aplicat-o e re-hashing-ul leneș (lazy migration) direct pe flow-ul de login.
Workflow-ul e simplu:
- Utilizatorul trimite user-ul și parola.
- Verifici dacă hash-ul existent din DB este de tip vechi (bcrypt).
- Dacă e bcrypt, validezi parola cu bcrypt.compare(). Dacă e incorectă, dai reject.
- Dacă e corectă, generezi pe loc noul hash folosind Argon2id cu parola primită în request.
- Salvezi noul hash în baza de date și finalizezi autentificarea.
În vreo două luni de la rollout, 85% din utilizatorii activi au trecut invizibil pe Argon2id. Restul de 15% care nu s-au mai logat demult vor fi migrați automat când revin pe platformă, fără ca cineva să observe vreo întrerupere.
Voi ce folosiți în producție acum? Ați trecut deja pe Argon2id sau bcrypt cu cost 12+ e considerat suficient în threat model-ul vostru?