Hashing Password sul lato client per evitare ritardi sul server di gioco single-core? [duplicare]

9

Attualmente sto implementando un semplice sistema di login. Vorrei memorizzare in modo sicuro tutte le password utente nel mio database. Le password sono i componenti più importanti. Tutti gli altri dati utente non sono importanti. Se un account viene violato, fintanto che la password non può essere calcolata come ammenda; altri dati sono cose come: punteggio e data di creazione dell'account.

Suppongo che alcuni dei miei utenti utilizzeranno la stessa password come per altri siti. Quindi ho bisogno di assicurarmi che la password non possa essere letta da un potenziale hacker.

Posso generare l'hash sul lato client in qualche modo per evitare che un hacker veda la vera password?

Prima di dire che non dovrei farlo sul client. Il server ha un ciclo di gioco costante che deve essere eseguito e non voglio che il gioco torni ogni volta che qualcuno registra un account o tenta di accedere. Questo approccio richiederebbe una parte del carico del server.

EDIT: Poiché questa domanda è stata chiusa, mi piacerebbe elaborare. Passare al client mi consente di utilizzare molti più round quando eseguo l'hash della password, poiché ciò non influirà in alcun modo sul server o su altri utenti. Ciò rende anche molto più semplice impedire a un utente di inviare richieste di spam e rallentare il server.

    
posta Sidney de Vries 17.01.2017 - 15:14
fonte

3 risposte

20

I am assuming that some of my users will be using the same password as they are for other sites.

Nel contesto della protezione della password da utilizzare su altri siti (oltre al tuo), non ha importanza se hai la password lato client o sul lato server .

Tuttavia, a seconda del tuo ambiente client , (ad esempio i browser web) potresti avere difficoltà a trovare un'implementazione ben ottimizzata (strong) di un hash di password lente. (ad esempio Argon2 o BCrypt) Quindi, il tuo suggerimento di hashing sul lato client può essere pratico solo negli ambienti app in cui è disponibile crittografia nativa .

Ovviamente, l'hashing lato client non farà nulla per proteggere la password da essere utilizzata su il tuo sito . Un utente malintenzionato che ha rubato l'hash può semplicemente saltare la routine hash lato client e diventare autenticato con il server. (non fidarti mai del client) Fortunatamente, questo vettore di attacco può essere risolto lato server . (vedi sotto)

The server has a constant game loop that needs to run, and I don't want the game to lag every time someone registers an account or tries to login. This approach would take some of the load off the server.

Come sapete, è tradizionalmente raccomandato hash sever-side. Se sei preoccupato per il caricamento, invio alcuni suggerimenti:

  1. Il fattore di lavoro dovrebbe essere regolato solo per prendere ~ 100ms sull'hardware di destinazione. (il tuo server) Quindi, non è un gran problema, vero? Normalmente sostengo 50ms-500ms, ma il tuo sito potrebbe usare un valore più basso e comunque essere considerato robusto.

  2. L'hash dovrebbe essere in un thread separato dal tuo ciclo di gioco principale (async) in modo che il gioco possa continuare a funzionare (anche se con prestazioni leggermente inferiori) mentre l'hash sta calcolando.

  3. Dovresti includere qualche forma di protezione DoS per limitare la quantità di hash che il tuo server calcolerebbe. In genere, il sito limiterebbe i tentativi di accesso (per utente?) In modo che un utente malintenzionato non fosse in grado di eseguire correttamente la forza bruta. Tale accelerazione impedirebbe un calcolo hash senza fine.

  4. Se lo desideri, puoi inserire la password su entrambi il del Cliente e il Server , se il l'ambiente client ha un supporto nativo sufficiente. (descritto sopra) Quindi è possibile ottenere un fattore di lavoro ancora più piccolo sul lato server.

    Se il lato client ha un fattore di lavoro sufficientemente strong, allora diventa ragionevole eseguire solo un rapido SHA-2 (sul lato zero) sul lato server, e questo risolverà completamente il problema. ( ringraziamenti @HenningMakholm )

Infine, assicurati che il client invii la password (o hash) su solo HTTPS . Questa è la cosa più importante, poiché nessuna quantità di presunto hashing protegge le password digitate in un sito HTTP.

    
risposta data 17.01.2017 - 15:30
fonte
5

Se l'obiettivo è solo per proteggere gli utenti dal riutilizzo della password quando il database è compromesso, allora sì, puoi spostare l'hashing sul lato client.

Devi accettare che questo è in generale insufficiente per proteggere effettivamente la tua applicazione. Non è sufficiente perché, in generale, la maggior parte di questi approcci ha uno dei due difetti:

  1. Si trasmetti un token che è "simile a una password", nel senso che se io faccio rompi le tue ipotesi su HTTPS o qualsiasi altra cosa, posso accedere come te.

  2. Memorizzano un token che è "simile a una password", nel senso che se io do guardi una riga nella tabella degli utenti, posso accedere come utente.

Il primo è qualsiasi manipolazione lato client che termina con "quindi trasmetto al server, il server lo hashing e il server confronta se l'hash è uguale a qualcosa nel database". Il secondo è caratteristico degli schemi di risposta alle sfide: "Ti mando questa stringa, la crittografi con la tua chiave, rimandi la versione crittografata e vedo se riesco a decifrarlo per ottenere di nuovo la sfida originale".

Ho scelto le parole per il secondo caso con molta attenzione perché rivela che in realtà puoi evitare questi due se il tuo sistema è basato su crittografia asimmetrica , chiavi pubbliche e chiavi private. Il tuo server può memorizzare una chiave pubblica se il tuo cliente può calcolare una chiave privata. Questo era completamente irrealizzabile con RSA ecc. ("Oh, userò semplicemente la password come seme per un generatore di numeri casuali deterministici e eseguirò l'impostazione dei tasti ogni volta" - stai scherzando?) Ma è diventato più possibile con crittografia a curva ellittica, in cui la chiave privata può essere letteralmente una semplice stringa di bit arbitraria di una certa lunghezza. Usi una funzione di derivazione della chiave per ottenerlo e sei al sicuro.

Tuttavia, potresti non voler mai "crearti la tua" crittografia in ogni caso: in tal caso, cerca un'implementazione del protocollo SRP (Secure Remote Password) creato a Stanford; ha visto un sacco di crittoanalisi ed è stato in giro per un po 'e probabilmente ha implementazioni che è possibile trovare e utilizzare.

    
risposta data 17.01.2017 - 16:38
fonte
3

Puoi fare la parte costosa dell'hash delle password sul lato client, ma devi fare attenzione. Ad esempio, il seguente protocollo sarebbe sbagliato :

  1. Il client stabilisce un canale autenticato e riservato sul server. (Ad es., Una connessione SSL con un certificato server valido.)
  2. Il client invia username al server
  3. Il server cerca la voce della password corrispondente (username, salt, hashed_pwd)
  4. Il server invia salt al client.
  5. Il client applica la sua password con un hash di password costoso: client_hash = pwhash(salt, pwd)
  6. Il client invia client_hash al server.
  7. Server confronta client_hash a hashed_pwd ; l'utente è autenticato se è uguale.

Quel protocollo sarebbe insicuro perché gli hash che il server memorizza sarebbe "equivalente alla password"; un hacker che ha rubato il database delle password del server sarebbe in grado di riprodurre gli hash sul protocollo per impersonare qualsiasi utente. Quindi il server ancora deve eseguire l'hashing salato ; ciò che può fare è spostare i calcoli più costosi sul client in modo che il server debba solo calcolare un hash veloce salato.

Un protocollo migliore sarebbe questo:

  1. Il client stabilisce un canale autenticato e riservato sul server. (Ad es., Una connessione SSL con un certificato server valido.)
  2. Il client invia username al server
  3. Server cerca la voce della password corrispondente (username, client_salt, server_salt, hashed_pwd) . (Questo è un passaggio modificato rispetto al protocollo errato: il buon protocollo ha due sali, uno per il client da usare, uno per il server.)
  4. Il server invia client_salt al client.
  5. Il client applica la sua password con un hash di password costoso: client_hash = pwhash(client_salt, pwd)
  6. Il client invia client_hash al server.
  7. Il server calcola server_hash = fast_salted_hash(server_salt, client_hash) . La funzione fast_salted_hash potrebbe essere HMAC o Blake2, digitata con server_salt . (Questo è un passaggio aggiuntivo che non esisteva nel protocollo non valido.)
  8. Server confronta server_hash a hashed_pwd ; l'utente è autenticato se è uguale.

Salendo l'hash della password sul lato client, significa che gli utenti che scelgono la stessa password invieranno hash diversi sul filo, in modo che un hacker che compromette un client e apprenda il suo client_hash non possa riprodurlo per accedere come utente con la stessa password.

Memorizzando solo un hash salato del client_hash , difendiamo dagli aggressori che rubano il database delle password, proprio come nel convenzionale hashing delle password.

    
risposta data 17.01.2017 - 20:45
fonte

Leggi altre domande sui tag