La risposta breve è, ovviamente, hai un bug (critico) nel tuo codice di hashing. Così com'è, chiunque può probabilmente accedere come qualsiasi utente, perché per qualche motivo la funzione hash della password produce sempre lo stesso risultato.
Ci sono diversi modi in cui questo errore potrebbe verificarsi, nessuno dei quali è intrinsecamente ovvio. Una cosa da considerare sicuramente, però: stai effettivamente includendo la password nei dati che hai inserito nella funzione hash o stai terminando l'hash senza aggiungere la password?
Un altro rischio è che il bug si trovi effettivamente nel codice del tuo database e, quando crei / aggiorni l'hash della password di un utente, lo stai accidentalmente impostando per tutti utenti, anziché solo uno specifico creato / aggiornato. Questo è altamente sfruttabile: creo il mio account e poi utilizzo la mia password per accedere a un account di un utente arbitrario, perché il loro hash è stato cambiato in mio.
OK, abbastanza ipotesi. Le cose realmente importanti qui sono che, francamente, non dovresti scrivere il tuo sistema di autenticazione. Anche lasciando da parte un bug critico che davvero, davvero non dovrebbe mai accadere - dovresti averlo trovato durante lo sviluppo o i test unitari, se non altro - il tuo sistema non è sicuro.
- Non dovresti usare MD5 per qualsiasi cosa , ha noti punti deboli ed è considerato crittograficamente rotto. Dovresti utilizzare la famiglia SHA2 di funzioni hash per tutto ciò che richiede un hash veloce; anche SHA1 è considerato deprecato per il nuovo codice.
- Non dovresti mai usare un hash veloce per memorizzare le password. Le password devono essere sottoposte a hash con una funzione hash volutamente lenta e costosa, in modo tale che se qualcuno scarica il database delle password, è difficile forzare la hash della password che contiene perché ogni round della forzatura bruta richiede un po 'di tempo.
- Usando un hash rapido a giro singolo, l'hardware di base (come le schede grafiche di fascia alta) può calcolare miliardi di hash al secondo, consentendo un cracking assurdamente rapido delle password. Invece, usa le funzioni che sono destinate alla generazione di chiavi o all'archiviazione della password.
- PBKDF2 è il più comune, ma è anche il più vecchio e meno costoso di un semplice hash veloce. Bcrypt è migliore, ma contro l'hardware moderno non è più molto buono. Scrypt, con i giusti parametri, è l'opzione moderna generalmente accettata. Esiste anche Argon2, un nuovo algoritmo progettato specificamente per l'hashing delle password, e il vincitore di una competizione triennale per determinare il miglior algoritmo del genere, se si vuole essere all'avanguardia.
- Non menzioni i sali per utente; li stai usando? Salire le password è assolutamente essenziale, altrimenti un utente malintenzionato può semplicemente generare una tabella arcobaleno per qualsiasi schema di hashing che si utilizza. I sali per utente interrompono questo attacco, e significano anche che (in situazioni normali) anche se due utenti scelgono la stessa password, non si può dire che lo abbiano fatto semplicemente guardando il database; i loro hash sono diversi. Tutti i buoni schemi di hashing della password sono salati. I sali dovrebbero essere generati casualmente e sono solitamente lunghi almeno 16 byte (128 bit).
A questo punto, devo proprio dire: dovresti usare un sistema di autenticazione scritto da qualcuno che abbia familiarità con questi sistemi e che abbia una versione ben collaudata e pronta all'uso. Non provare a scrivere tali funzioni critiche per la sicurezza finché non comprendi meglio l'area.