Folosește token-uri de resetare a parolei unice, aleatorii și cu expirare scurtă

Subiect din roadmap-ul Bune practici: securitatea API-urilor · parte din „Autentificare”

Această practică implică generarea unui șir unic, criptografic aleatoriu pentru fiecare cerere de resetare a parolei, care devine invalidă imediat ce este utilizată sau după o perioadă scurtă (de obicei 15-60 de minute). Este esențială deoarece previne atacurile de tip replay, unde un hacker interceptează sau furește un token valid și îl folosește ulterior pentru a prelua controlul contului. Dacă ignori acest aspect, chiar și un token expirat sau consumat ar putea rămâne activ, transformând o simplă funcționalitate de recuperare într-o vulnerabilitate critică de acces neautorizat.

Cum o aplici

  1. Generare sigură: Folosește un generator de numere aleatoare criptografic (CSPRNG) pentru a crea token-ul. Evită Math.random() sau ID-urile incrementale.
  2. Stocare sigură: Salvează hash-ul token-ului în baza de date, nu textul simplu. Asociază-l cu ID-ul utilizatorului, data expirării și un flag used.
  3. Expirare strictă: Setează un TTL (Time-To-Live) scurt în baza de date sau folosește coloane cu tip DATETIME pentru verificare la fiecare cerere.
  4. Invalidare imediată: Marcare token ca used=true în aceeași tranzacție atomică cu generarea parolei noi.

Exemplu

Varianta incorectă expune token-ul în URL și nu verifică expirarea:

// GREȘIT: Token vizibil și fără expirare reală
const resetLink = `/reset-password?token=${userId}&code=123456`;

Varianta corectă folosește hash și verifică timpul:

// CORECT: Hash și verificare timp
const crypto = require('crypto');
const token = crypto.randomBytes(32).toString('hex');
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');

// În baza de date se stochează hashedToken + expires_at
// La cerere:
if (Date.now() > user.resetTokenExpiresAt || user.isResetTokenUsed) {
  throw new Error("Token invalid sau expirat");
}

Cum verifici

  • Teste de integrare: Scrie teste care încearcă să utilizeze același token de două ori consecutiv; al doilea apel trebuie să eșueze.
  • Verificare temporală: Simulează trecerea timpului (sau modifică ceasul serverului) pentru a valida că token-urile vechi sunt respinse automat.
  • Audit log: Verifică dacă sistemul generează evenimente de succes/eșec pentru fiecare cerere de reset, facilitând detectarea tentativelor brute-force.

Greșeli frecvente

  1. Stocarea token-ului în clar: Dacă baza de date este compromisă, atacatorul poate reseta orice parolă fără a ști parola curentă.
  2. Lipsa invalidării după utilizare: Un token care rămâne valid după schimbarea parolei permite accesul repetat la contul victimei.
  3. Timp de expirare prea lung: Perioade de 24 de ore sau mai mult cresc fereastra de oportunitate pentru interceptarea și reutilizarea token-urilor.

Resurse gratuite

Alte subiecte din „Autentificare”