Questo schema di autenticazione password fai da te è accettabile?

1

Questo è principalmente un esperimento mentale per la comunicazione client / server, e voglio conoscere i difetti.

Quando viene creato un account utente (con U come username e P come password,) Genero un salt casuale ( S ) e memorizzo questi valori nel database (sul lato server) : U , S e H che è calcolato come H = hash(U+S+P) .

Durante l'autenticazione di un utente:

  1. Il client prima "tenta un'autenticazione" inviando U al server.
  2. Il server crea un codice di sfida ( R ) per quell'utente e lo memorizza nel database, insieme al tempo in cui questa sfida scadrà ( T ) e invia R e S al client .
  3. Il client calcola la propria versione di H (per hashing U e S e P insieme, ha U e P e ha ricevuto S dal server.)
  4. Il client calcola quindi un nuovo valore G come G = hash(H+R) e invia questo G al server ("richiesta di autenticazione" effettiva).
  5. Il server ha hash il proprio H insieme a R per ricostruire G e autentica l'utente se il suo G corrisponde al valore ricevuto dal client e T non è passato ancora.
  6. Se l'autenticazione ha esito positivo o negativo, R viene rimosso dal database del server.

I difetti di cui sono già a conoscenza sono questi:

  • Quando si crea un account, la password viene trasmessa in chiaro. Questo può essere mitigato utilizzando un servizio di creazione di account dedicato che utilizza SSL per la creazione di account.
  • Se si tenta di eseguire l'autenticazione, alcune risorse verranno allocate sul server. Questo può essere mitigato consentendo solo un (o un numero fisso) di codici challenge per utente.
  • Cercando di scoprire nomi utente e sali validi generando molti tentativi di autenticazione; che il server può sventare inviando un codice salt salt e challenge anche se l'utente non esiste.

Ecco le mie domande specifiche:

  1. Cosa mi manca? Dov'è il disastro in attesa di accadere?!
  2. Che cosa posso fare per rendere questo più sicuro / migliore? Oltre all'utilizzo di SSL e all'invio di password in chiaro (solo testo in chiaro dalla prospettiva della mia applicazione).
  3. Sto pensando a SHA-256 per tutti gli hash. Ci sono difetti nella famiglia SHA-2? Ishing i valori una volta sufficiente per generare H e G ?
  4. Per generare H e G , le altre permutazioni dei valori sono migliori? per esempio. P+U+S , R+H , ecc.
  5. Quali comodità sto negando ai miei utenti? (A parte le loro autenticazioni che ora richiedono due round trip sul server.)

UPDATE : In definitiva, voglio fare questo:

Dopo una corretta autenticazione, il server genera una chiave di sessione K come: K = hash(H+F) dove F è una stringa casuale. F viene inviato all'utente e K viene mantenuto nel database. Il client ricostruisce K utilizzando il F ricevuto e crittografa tutte le comunicazioni con il server d'ora in poi con un codice simmetrico (ad es. AES) con K come chiave.

    
posta yzt 25.05.2015 - 22:44
fonte

1 risposta

8

Il tuo problema principale può essere riassunto come segue: dov'è l'SSL?

Qualsiasi intercettatore, osservando gli scambi, otterrà informazioni sufficienti per eseguire un attacco del dizionario offline : l'attaccante sarà in grado di "provare le password" ricalcolando i valori hash rilevanti e vedere se corrispondono a quello che è stato osservato. Questo è "offline" perché l'utente malintenzionato può eseguire tutto ciò sui propri computer, senza interagire con il client o il server. L'attaccante può fare tutto questo alla velocità delle sue macchine e, grazie al fatto che le solite funzioni di hash si adattano molto bene a ciò che possono fare CPU e GPU moderne, sarà in grado di provare miliardi di password al secondo. Non molte password dureranno a lungo in queste condizioni.

Potresti provare a fare qualche precedente Diffie-Hellman per ottenere una chiave di crittografia condivisa, e criptare tutto con quello, ma hai appena spostato il problema a quello di creare un Man-in-the-the- Attacco centrale : pensi di parlare con il server, ma stai davvero parlando con l'attaccante, con cui fai lo scambio di chiavi DH. L'utente malintenzionato torna quindi alla situazione precedente e può osservare gli hash che gli consentono di eseguire un attacco di dizionario offline.

La soluzione normale consiste nel configurare prima un tunnel sicuro per il server, che garantisce almeno al client che sta parlando al server previsto e nessun altro. Questo è chiamato SSL (o TLS , che è il suo nome "standard"). Una volta creato un tunnel, è possibile utilizzare un metodo di autenticazione "show the password" molto più semplice e il tunnel garantirà anche che tutti gli scambi di dati successivi siano collegati a tale autenticazione (ad es. Gli hacker non saranno in grado di dirottare la presa dopo i passaggi di autenticazione).

SSL presuppone che il client abbia un modo per verificare l'identità del server - questo è il punto del certificato del server. Se si vuole fare a meno del certificato e ottenere l'autenticazione reciproca basata su password del client e del server, ma senza rivelare nulla che consentirebbe agli aggressori di eseguire attacchi dizionario offline (anche attaccanti attivi che tentano di impersonare il client o il server) , quindi è necessario uno di questi algoritmi scambio di chiavi autenticati . Anche in questo caso, utilizza SSL, con suite di crittografia SRP . Gli unici protocolli noti che riescono a un'autenticazione basata su password senza certificato, senza offrire attacchi di dizionario offline, usano alcuni metodi matematici; non ci riuscirai semplicemente usando le funzioni di hash.

Indipendentemente dal protocollo di autenticazione , hai ancora bisogno di un funzione di hashing della password sicura per tutto ciò che memorizzi sul lato server, per evitare di trasformare un'intrusione parziale di sola lettura (ad esempio attraverso un'iniezione SQL) in una festa che rompe la password.

E, naturalmente, nella crittografia, "fai-da-te" è la strada più veloce per l'inferno.

    
risposta data 26.05.2015 - 02:45
fonte

Leggi altre domande sui tag