Prendiamo alcune note alle risposte precedenti.
In primo luogo, probabilmente non è la migliore idea utilizzare algoritmi hash lato client. Se la tua password è salata sul lato server, non sarai in grado di confrontare gli hash (almeno non se non archivi l'hash del client nel database in uno dei livelli di hashing della password, che è lo stesso o peggio). E non vuoi implementare l'algoritmo di hashing utilizzato dal database sul lato client, sarebbe sciocco.
In secondo luogo, nemmeno il trading di chiavi crittografiche non è l'ideale. Il MITM potrebbe teoricamente (considerando che ha un certificato di root installato sul client) modificare le chiavi crittografiche e modificarle con le proprie chiavi:
Connessione originale (non considerando tls) da un server teorico che scambia le chiavi:
Il client richiede le chiavi pubbliche> il server detiene le chiavi private, genera le chiavi pubbliche al client> il server invia le chiavi pubbliche al client
Ora, in una traccia teorica MITM:
Il client richiede le chiavi pubbliche> MITM genera chiavi private false > Il server detiene le chiavi private, genera chiavi pubbliche per il client> MITM riceve le chiavi pubbliche dal server originale, ora siamo liberi di inviare le nostre chiavi pubbliche false al client e ogni volta che una richiesta arriva dal client, decifreremo i dati del client con le chiavi false, cambieremo il payload (o lo leggeremo) e crittograferemo con le chiavi pubbliche originali > MITM invia chiavi pubbliche false al client.
Questo è il punto di avere un certificato CA attendibile in TLS, ed è così che ricevi un messaggio di avviso del browser se il certificato non è valido.
In risposta all'OP: a mio modesto parere non puoi farlo, perché prima o poi qualcuno vorrà attaccare un utente dal tuo servizio e proverà a violare il tuo protocollo.
Quello che puoi fare, tuttavia, è implementare 2FA per impedire alle persone di tentare di accedere con la stessa password. Beaware di replay attack, però.
Non sono bravo con la crittografia, per favore correggimi se sbaglio.