Il seguente schema di autenticazione è sicuro?

7

Stavo cercando di progettare un sistema di autenticazione che renderebbe molto più difficile indovinare una password tramite la forza bruta e ridurre il rischio per un utente se la password con hash è stata rubata tramite un attacco basato sullo snooping. Inoltre, dal momento che il mio codice client può essere facilmente visualizzato da coloro che desiderano vederlo (è in un linguaggio interpretato, tuttavia, crittografo e offusisco il client distribuito), volevo essere in grado di impedire a un utente malintenzionato di guardare la fonte per impersonare facilmente un utente. La sicurezza attraverso l'oscurità è NON sicurezza.

Ecco l'algoritmo che ho ideato. Volevo sottoporlo a un esame pubblico perché gli algoritmi di crittografia funzionano sempre meglio se sottoposti a più opinioni possibili, IMHO.

(Tutti gli hash sono calcolati con SHA-2 e una dimensione di blocco di 512 bit. Questo algoritmo non è vulnerabile a eventuali collisioni o attacchi pre-immagine ed è una funzione di hash crittografica sicura.)

[CLIENT LATO]

  1. L'utente fornisce un nome utente di qualsiasi carattere / simbolo / numero inferiore a 30 caratteri e una password di qualsiasi carattere / simbolo / numero compresa tra 8 e 200 caratteri.

  2. Il nome utente è hash.

  3. L'hash del nome utente viene aggiunto alla fine della password dell'utente come salt.

  4. La password salata viene sottoposta a hash e quindi hash hash.

  5. La data e l'ora correnti vengono richieste dal server di autenticazione e vengono quindi sottoposte a hash.

  6. L'hash del timestamp viene aggiunto all'hash username / password come quello che chiamerò "sale dipendente dal tempo". Quest'ultima combinazione viene quindi sottoposta a hash per produrre l'hash di autenticazione finale.

  7. Il nome utente, l'hash con data e ora, la password salata e il tempo impiegato per generare il sale dipendente dal tempo vengono inviati al server tramite una connessione TLS / SSL.

[SERVER SIDE]

  1. Il server verifica che il timestamp ricevuto sia nell'ultimo minuto. Se non lo è, il server indicherà che l'autenticazione è fallita.

  2. Il server ha il nome utente / password salata e lo confronta con l'hash salato / password del database memorizzato. Se non corrispondono l'autenticazione fallisce. (Per chiarire, il server ha un hash hash della password salata che verifica contro un hash dell'hash della password salato dato dal client.)

  3. Il server calcola un hash del timestamp inviato dal client.

  4. Il server annulla l'hash del timestamp generato e l'hash della password salata per formare l'hash di autenticazione.

  5. Confronta l'hash di autenticazione prodotto con l'hash di autenticazione inviato dal client. Se sono uguali, segnala l'autenticazione. Altrimenti segnala un errore di autenticazione.

Se sono corretto, credo che questo schema di autenticazione faccia davvero impazzire una password bruta e rende la password rubata tramite lo snooping utile solo per un minuto intero.

Tuttavia, ciò a cui non protegge, come penso sia impossibile, è il furto di password da parte dell'utente quando vengono inserite nel client. Lo spyware sarebbe in grado di rubare il nome utente e la password effettivi.

EDIT 1 :: Risolto il problema con il processo di autenticazione in modo che il server non memorizzasse l'hash della password salata, solo un hash di quel valore. Ciò impedisce a un utente malintenzionato con accesso al database di conoscere la password originale. Il motivo per cui questo deve essere fatto è il valore hash della password salata. Hash è la password dal punto di vista del server. Memorizzare l'hash della password salata nel database equivale a memorizzare tutte le password dell'utente in testo semplice.

EDIT 2 : risolto lo schema in modo che l'autenticazione si basasse sull'ora del server, non sul client.

EDIT 3 :: Ha reso la lunghezza della password meno restrittiva, ma l'ha mantenuta ragionevole.

    
posta Josh 02.08.2011 - 14:02
fonte

8 risposte

9

Se passa attraverso SSL / TLS, che garantisce l'autenticazione del server (il client è sicuro che stia parlando con il server giusto) e la riservatezza e l'integrità dei dati trasmessi, allora non c'è ficcanaso da temere - o, piuttosto, , se si verifica lo snooping, deve essere corretto sul client o sul server, a quel punto si hanno problemi più grandi (se un utente malintenzionato può leggere direttamente i dati inviati sul client, probabilmente può anche registrare le sequenze di tasti).

Se consideriamo il tuo schema di hashing delle password da solo (cioè senza prendere in considerazione SSL / TLS), allora ha alcuni problemi:

  • includi il tuo "sale" semplicemente aggiungendolo. Non ci sono prove che ciò non causerà problemi con SHA-512. SHA-512 è una funzione di hash Merkle-Damgård , il che significa che è un po 'meno che ideale; ha una struttura (ad esempio "attacco di estensione della lunghezza"). Questo non significa che SHA-512 sia rotto; solo che lo gestisci come se fosse un Random Oracle mentre è "solo" resistente a collisioni e preimmagini.
  • Non si itera attraverso un numero sufficiente di invocazioni della funzione di hash. Ciò rende il processo troppo veloce: un utente malintenzionato che osserva l'hash risultante può "provare" potenziali password e sarà in grado di farlo ad alta velocità (milioni di password al secondo, con un semplice PC). Questo è chiamato "attacco dizionario" e tende a funzionare perché gli utenti sono cattivi nella scelta e nella memorizzazione di password sicure.
  • Si utilizza SHA-512 anziché SHA-256. Parli di un "linguaggio interpretato": se questo è Javascript, allora quel linguaggio è grossolanamente inefficiente con le operazioni a 64 bit (SHA-512 ne è pieno), quindi usare SHA-512 invece di SHA-256 limita strongmente il numero di iterazioni che è possibile eseguire sul sistema client; questo aumenta di conseguenza l'efficacia dell'attacco del dizionario.

Le raccomandazioni abituali per l'hashing della password sono PBKDF2 , bcrypt e scrypt (il mio preferito è bcrypt; PBKDF2 non è stato inizialmente progettato per questo e scrypt è ancora troppo nuovo per essere generalmente attendibile).

Esistono protocolli di autenticazione che sono, per impostazione, immuni agli attacchi del dizionario offline: sono chiamati Scambio di chiavi con autenticazione tramite password . I protocolli PAKE consentono l'autenticazione reciproca basata su password tra client e server, in modo tale che un aggressore snooping o anche un utente malintenzionato che impersona il client o il server non possa apprendere nulla che gli consenta di "provare le password" da solo sistemi. L'autore dell'attacco è limitato agli attacchi del dizionario online : ogni ipotesi di password implica l'interazione con il client o il server. Il protocollo PAKE più conosciuto è SRP che è stato integrato in SSL / TLS . Con TLS + SRP, si ottiene un tunnel di dati sicuro in cui il server e il client sono reciprocamente autenticati in relazione alla password, senza alcun certificato (la parte più brillante di esso). Come bonus, il server non ha bisogno di memorizzare la password in chiaro, solo un valore derivato da esso (come se fosse hash) quindi un utente malintenzionato che scarica il database del server non impara le password (egli impara abbastanza per eseguire un attacco al dizionario offline, però). GnuTLS è una libreria che implementa SSL / TLS con supporto SRP.

    
risposta data 02.08.2011 - 19:32
fonte
9

A prima vista sembra che chiunque abbia la tabella delle password possa accedere come utente. Salta semplicemente i passaggi 1-4 del client e sostituisce l'hash che ha ottenuto dal db. Quindi il tuo schema è molto debole in questo scenario.

Perché non usi semplicemente l'hashing della password standard? La maggior parte degli attacchi di intercettazione è già prevenuta se si utilizza SSL / TLS e si convalida l'impronta digitale del server contro una lista bianca.

O se sei paranoico usa una buona implementazione di SRP . Ma non implementarlo da solo. È molto facile produrre una cattiva implementazione di esso che sembra funzionare ma non è sicuro.

    
risposta data 02.08.2011 - 16:00
fonte
5

Non riesco a vedere quello che stai cercando di realizzare con questo schema, che non può essere fatto da un metodo ben noto e provato già.

Prima di tutto, non puoi dipendere dall'ora del cliente. Molte persone non sincronizzano il loro orologio e dovresti prendere in considerazione i fusi orari.

In secondo luogo, l'attaccante può passare attraverso lo schema di autenticazione tutte le volte che gli piace per la forza bruta, come indicato. Puoi aggiungere funzionalità di blocco, ma puoi aggiungerla a qualsiasi schema.

In terzo luogo, il tuo schema impedisce la riproduzione del POST di autenticazione, ma usando il tempo, che è una cattiva idea a causa dei problemi di sincronizzazione. Un'idea migliore sarebbe la sfida-risposta, un meccanismo ampiamente accettato per la garanzia di freschezza.

Se includessi un token di sfida nell'hash, un hash intercettato non fornirebbe nemmeno l'accesso per un minuto: potrebbe essere utilizzato solo una volta.

Ti consiglio di implementare l'autenticazione a due fattori se sei preoccupato dell'autenticazione e non vuoi fidarti di SSL. Puoi utilizzare challenge-response in combinazione con hash salati e allungati per evitare replay e cracking offline.

    
risposta data 02.08.2011 - 18:19
fonte
5

Dovrò unirmi a quelli che dicono "smetti di provare a progettare il tuo sistema crittografico". Non sei abbastanza intelligente. Non sono abbastanza intelligente Se non hai trascorso dieci anni a lavorare sul problema, non puoi farlo.

Perché avere lunghezze massime? Lo farai sempre in ogni caso. Lascia che abbiano una password di un milione di caratteri se lo desiderano, non ha importanza, perché memorizzi solo i 32 byte dell'hash finale, non i milioni di byte della password.

Ad alcune persone piacciono le frasi pass, che potrebbero essere una lunga frase di 100 caratteri. Posso digitare una password di 100 caratteri usando una frase più veloce di una password complicata con caratteri speciali.

Non basare il sale sul nome utente. Usa informazioni completamente casuali e genera un nuovo salt ogni volta che l'utente cambia la password. In caso contrario, un hacker potrebbe precomporre un dizionario di grandi dimensioni per un utente e ripetutamente hackerare l'account anche quando l'utente cambia la password.

Sembra che tu pensi in termini di scelta della funzione hash più sicura possibile. La realtà è che SHA-512 non sarà più sicuro di MD5 in tali applicazioni, specialmente se si utilizza il rafforzamento delle chiavi. Ripetendo MD5 un migliaio di volte è molto più sicuro di SHA-512. La sicurezza è un compromesso: scegliere l'algoritmo di hash che è più facilmente eseguito sul client, che è probabilmente SHA-1 o SHA-256, non il più "sicuro" possibile.

SSL ha già una protezione di riproduzione. Perché complicare il tuo sistema di autenticazione facendo il tuo? Sebbene, a causa di SSL, si abbia la certezza che gli orologi non siano troppo lontani (altrimenti SSL fallirebbe).

Anche se fai qualcosa di sbagliato, ad esempio usando un semplice hash MD5, gli hacker non saranno in grado di violare più del 50% delle password sul tuo sito. Viceversa, se si fa tutto bene, gli hacker saranno comunque in grado di decifrare il 20% delle password attraverso una modifica del dizionario leggermente mutata. Qualunque cosa tu faccia, non puoi impedire che alcune password vengano violate se il database è compromesso. Invece, il tuo obiettivo dovrebbe essere quello di fare le cose standard per minimizzare gli hack, come PBKDF2 con sali e rafforzamento delle chiavi.

Inoltre, non importa quanto tempo passi su questo, è probabile che tu faccia altri errori comuni, come inviare i cookie di sessione in chiaro.

In definitiva, quello che sto cercando di dire è: smetti di provare a progettare il tuo sistema crittografico. Ripeti lo stupido meme "l'oscurità non è sicurezza" senza comprenderlo veramente, eppure ti rifiuti di seguire il consiglio comune di smettere di provare a progettare il tuo sistema crittografico.

    
risposta data 03.08.2011 - 20:20
fonte
3

Non vedo come questo possa rendere il bruto forzare più duramente dal lato client. Potrei semplicemente automatizzare il passaggio della tua applicazione a un elenco di username / password fino a quando non si lavora. Se avessi accesso al tuo database, renderebbe quasi impossibile forzare le password con le tabelle arcobaleno (se questo è ciò che intendi per protezione). Ma dovrai ancora salvare il sale con il nome utente + password hash (e presumibilmente potrei decodificare il tuo schema di hashing), così potrei generare una tabella arcobaleno per una voce nel tuo database, se stavo bersagliando un utente specifico, o volevo solo un account.

Per quanto riguarda la prevenzione delle forzature brute lato client, è possibile inserire un blocco temporale all'accesso dopo un tentativo fallito. Dopo ogni tentativo fallito, l'utente deve attendere 2 ^ (tentativi falliti) secondi prima di poter tentare un altro accesso. Questo dovrebbe essere forzato lato client e server. Assicurati anche di pensare a come un utente malintenzionato potrebbe utilizzare il tuo schema come DoS per un altro utente.

    
risposta data 02.08.2011 - 15:25
fonte
2

Non lo vedo menzionato altrove, quindi ne parlerò qui: il tuo sale non è particolarmente sicuro. Il punto (unico) di un sale è quello di rendere gli attacchi di precomputazione come le tabelle arcobaleno poco pratici, e ciò è più efficace se non c'è modo di indovinare il sale, e ha una vasta gamma di valori possibili.

Usando il nome utente, ci si assicura che la stessa combinazione utente / password abbia sempre lo stesso hash. Poiché esiste un numero limitato di nomi utente comuni, un utente malintenzionato può ancora precalibrare gli hash per tali nomi utente. Hai moltiplicato lo sforzo richiesto dal numero di nomi utente comuni, ma non è intrattabile. L'uso di un sale casuale, come è prassi normale, introduce un moltiplicatore molto più grande.

Infine, aggiungerò un plug in più per la brigata "non inventare i tuoi criptosistemi". Esistono già sistemi ben collaudati che fanno ciò che stai cercando di fare, come illustra l'eccellente risposta di Thomas. Usa uno di loro, non inventarne uno tuo.

    
risposta data 03.08.2011 - 03:56
fonte
1

Sembra che tu abbia perso il punto di hashing di una password. Il punto di hashing della password è il seguente:

1) Il server memorizza solo la password con hash.

2) L'utente deve fornire al server la password unshed.

3) Quindi qualcuno che ruba il database delle password dal server continua a non sapere cosa dare al server a meno che non imponga la password.

Hai fatto questo:

1) Il server memorizza solo la password con hash.

2) L'utente fornisce al server la password con hash.

3) Quindi qualcuno che ruba il database delle password dal server può impersonare qualsiasi utente, indipendentemente dalla sua password.

Ai fini della valutazione dell'algoritmo server-client, la "password" è l'informazione minima necessaria per autenticare con successo il server. Nel caso del tuo algoritmo, la "password" è quindi l'hash dell'hash creato nel passaggio 4, e questo è esattamente ciò che è memorizzato sul server. Quindi stai memorizzando password non trattate / non crittografate. Non va bene.

    
risposta data 30.08.2011 - 15:56
fonte
0

Forza bruta sembra quasi impossibile, in effetti il modo più veloce per risolvere il problema è uno sniffer tcp per mostrare i dati inviati al server (nome utente hash, password e datetime) e utilizzarlo in una nuova richiesta al server.

Se il tuo server controlla il datestamp dal client per verificare se non è "vecchio" allora 1 minuto, il tuo cliente dovrà autenticarsi ogni minuto. È comunque possibile utilizzare uno sniffer tcp per rilevare questo.

Per evitare questo SSL potrebbe essere una soluzione.

    
risposta data 02.08.2011 - 14:10
fonte

Leggi altre domande sui tag