Se vuoi sicurezza, trasmettere i dati di autenticazione tramite TLS è un grande inizio.
Ma supponiamo che il websocket sia già configurato su TLS.
Una soluzione che raccomanderei sarebbe basata su un meccanismo di risposta alle sfide:
- Il server imposta una serie casuale di byte (la sfida), imposta un timeout al termine del quale la sfida non sarebbe autorizzata.
- Il client invierà "testo semplice" il nome utente e la sfida e un hash (con un algoritmo SHA2 o SHA3) di
challenge || username || f(password)
,
f(password)
è come la password è memorizzata nel database (un SHA256 di password
per esempio).
- Il server verifica i dati del nome utente e sfida la risposta e, in caso affermativo, autentica l'utente. Inoltre, invalida la sfida di invalidare qualsiasi tentativo futuro utilizzando questa sfida.
Questo metodo fornisce una funzionalità anti-replay: un utente malintenzionato non può acquisire i dati e riprodurli in seguito per l'autenticazione.
Tuttavia, ho un grosso problema con questo metodo: f(password)
ha qui la stessa sicurezza di password
: se il database perde, qualsiasi utente malintenzionato potrebbe autenticarsi come chiunque altro. Dico "all'incirca" perché, se conservato in chiaro, dal momento che molti utenti usano la stessa password su più siti web (che è male), i loro account potrebbero essere compromessi altrove.
Non riesco a pensare a un metodo di protezione contro una fuga di database e un meccanismo anti-replay, ma un meccanismo anti-database (invia password utente in chiaro su TLS, password hash con database salt e confronta con database) over TLS dovrebbe essere sufficiente contro la maggior parte dei rischi che incontrerai