SRP o WebCrypto challenge?

3

Per un nuovo sito Web (HTTPS con HSTS + HPKP), vorremmo limitare l'accesso all'accesso solo sui dispositivi dell'utente autorizzato. Per questo, c'è una chiave pubblica / privata WebCrypto ECDSA generata su ogni nuovo dispositivo. Il server memorizza la chiave pubblica del nuovo dispositivo e restituisce un ID dispositivo. Il browser salva in un IndexedDB denominato «dispositivo» la chiave privata (non estraibile) e l'ID del dispositivo.

Quando l'utente registra il suo account o desidera autorizzare un nuovo dispositivo, gli chiediamo una password per questo dispositivo, ma non vogliamo salvare la sua password nel database del server.

  • Potremmo usare il protocollo SRP e inviare il sale & «Verificatore» al server, ma piuttosto usando la password dell'utente, usiamo una password derivata (WebCrypto PBKDF2 o libreria Argon2)

  • Oppure potremmo usare nuovamente WebCrypto per creare nuove chiavi ECDSA, specifiche per questo utente su questo dispositivo, e inviare la chiave pubblica sul server. Sul browser, memorizziamo in un IndexedDB chiamato «base64 (SHA-256 (login)» questa chiave privata dell'utente ma crittografato (funzione wrapKey) con algoritmo AES-GCM e per la chiave usiamo la derivazione password utente (WebCrypto PBKDF2 o Argon2 libreria esterna) .Per effettuare il login, il server invia una sfida, una semplice stringa casuale, il client restituisce la firma di questa sfida con questa nuova chiave privata specifica dell'utente (quindi ha bisogno di conoscere la buona password per scartare la chiave).

Se il nostro DataBase è trapelato:

  • Con SRP, il verificatore non può permettere di indovinare facilmente la password dell'utente, ma suppongo che dobbiamo chiedere una nuova password a tutti i nostri utenti.

  • Con WebCrypto, è solo una chiave pubblica. Gli utenti non hanno bisogno di cambiare la loro password. EDIT: Uno svantaggio è che è possibile effettuare il controllo di più password sul lato client, ad esempio se ho saputo che la mia vittima potrei provare potrebbero essere 1000 password possibili sulla console JS per scartare la chiave privata dell'utente, senza la necessità di contattare il server .

Naturalmente, se i DNS indicizzati vengono cancellati sul browser, questo richiede all'utente di avviare un processo per recuperare il suo account (domanda privata, OTP via email, qualunque cosa ... non è l'argomento), ma questo non è specifico per l'opzione WebCrypto, è anche l'opzione SRP perché abbiamo bisogno di rilevare l'ID del dispositivo e controllarne la firma per essere sicuri che si tratti di un dispositivo autorizzato dall'utente.

Solo per informazione, aggiungiamo U2F dopo questa prima sfida di autenticazione.

Nel mio caso specifico, raccomandi di utilizzare SRP challenge o questa sfida WebCrypto per favore?

    
posta lakano 25.10.2017 - 20:01
fonte

1 risposta

0

Propongo questa soluzione per rispondere alla mia domanda:

Le chiavi di ECCCA WebCrypto sono davvero utili, ma se la usiamo come spiegato nella mia domanda (incapsulata con AES-GCM), è possibile che un codificatore JS vada sul browser della vittima e provi migliaia di password nella console JS per sapere se è la buona password o no, senza alcuna connessione al server. Quindi, è sicuramente meglio non permettere di provare la password senza interazione con il server. Ecco perché la mia soluzione è di mantenere le chiavi ECDSA del dispositivo, con chiave privata non estraibile, non crittografata e globale per tutti gli utenti su questo dispositivo.

SRP è ampiamente testato e ampiamente distribuito, tuttavia in caso di perdita DB, anche se è difficile recuperare la password dell'utente da brute-force, è possibile perché l'utente malintenzionato ha il sale SRP e il verificatore. Pertanto, la soluzione migliore è non utilizzare la password utente ma un OTP casuale e rinnovarlo a ogni connessione riuscita.

Innanzitutto, se il dispositivo non ha una chiave privata archiviata:

  • Genera nuove chiavi WebCrypto ECDSA
  • Invia questa chiave pubblica del dispositivo al server
  • Il server restituisce un deviceUUID e una sorta di JWT per le prossime richieste

Quando l'utente registra o autorizza un nuovo dispositivo:

  • Genera un OTP di 512 bit casuali
  • Genera un massimo di 128 bit casuali per l'OTP derivato
  • Ricava l'OTP con Argon2 512 bit, salt = derivedOTPSalt
  • Genera un massimo di 128 bit casuali per SRP
  • Crea il verificatore SRP per questo tasto derivato -P
  • Se l'utente ha un dispositivo U2F, registralo per questo dispositivo
  • Invia al server deviceUUID, SRP salt / verifier della chiave derivedOTP e U2F PublicKey. La richiesta è firmata con la chiave privata del dispositivo ECDSA.
  • Se la registrazione dell'utente viene accettata dal server, quindi, richiedere una password all'utente per questo dispositivo
  • Genera un massimo di 128 bit casuali per la derivazione della password
  • Ricava la password utente con Argon2 512 bit, salt = derivedPasswordSalt
  • Crea una chiave mascherata: OTP ^ derivedPassword (XOR)
  • Salviamo in un utente dedied DB IndexedDB / sha256 (login): maskedKey, derivedOTPSalt, derivedPasswordSalt, u2f = (vero / falso)

Quindi, quando l'utente desidera accedere:

  • Invia login e deviceUUID al server e richiedi sfide SRP / U2F (richiesta firmata dalla chiave privata ECDSA, come tutte le richieste al server)
  • Se la firma del dispositivo è ok, il server restituisce: challengeUUID, SRP Salt / B challenge e una sfida di testo casuale da firmare con il dispositivo U2F (anche se sappiamo che l'utente non ne ha uno)
  • Se l'utente ha un dispositivo U2F, firma la sfida o genera bit casuali (per ingannare qualsiasi MITM)
  • Richiedi la password dell'utente per questo dispositivo e derivane (Argon2, salt = derivedPasswordSalt)
  • Ottieni il risultato di maskedKey memorizzato ^ derivedPasswordAttempt (XOR)
  • Da questo risultato (in teoria, otteniamo l'OTP originale), quindi lo deriviamo con Argon2 / salt = derivedOTPSalt e creiamo da questo la risposta alla sfida SRP A / M1
  • Prepariamo anche il prossimo OTP seguendo il metodo di registrazione
  • Invia al server: challengeUUID, sfida U2F, sfida SRP A / M1 e il prossimo verificatore SRP & sale per il prossimo OTP.

Il server può confermare che è il buono OTP, la buona firma del dispositivo ECDSA e se l'utente ha un dispositivo U2F la buona firma U2F. Se tutto va bene, il server sostituisce il vecchio verificatore OTP / sale con il successivo e restituisce un nuovo JWT di autorizzazione.

Con questa soluzione, anche se il DB è stato trapelato, è impossibile recuperare la password dell'utente reale, è solo possibile recuperare l'OTP derivato, e non è sufficiente che l'hacker falsi l'identità dell'utente perché ha bisogno anche del chiave privata del dispositivo (e un possibile dispositivo U2F).

Per un MITM, non può leggere la password utente o OTP, ma può leggere ogni verificatore OTP / sale. Altrimenti, non è sufficiente perché ha anche bisogno della chiave del dispositivo privato e potrebbe essere il dispositivo utente U2F. Utilizziamo anche HTTPS con HSTS + HPKP per prevenire attacchi MITM.

Per un utente malintenzionato con accesso al dispositivo della vittima, può utilizzare la chiave privata del dispositivo e leggere i sali e la chiave mascherata, ma questo non dovrebbe aiutare a indovinare la password, anche con attacco a forza bruta sul lato client , perché ha bisogno di controllare se l'OTP è ok con una richiesta del server.

Questa soluzione resetta anche ogni volta una nuova OTP dopo ogni autentica riuscita. In caso di perdita DB, possiamo inviare una notifica PUSH a tutti gli utenti per chiedere loro di connettersi al servizio, per resettare il loro OTP.

Quindi, questa soluzione utilizza protocolli rispettati (SRP, chiavi del dispositivo ECDSA, verifica U2F, OTP, Argon2 / PBKDF2) e sono mescolati per aumentare la sicurezza.

Se un peer potrebbe rivedere questo progetto per indicare un punto di errore, ciò potrebbe essere molto apprezzato:)

    
risposta data 28.10.2017 - 13:47
fonte

Leggi altre domande sui tag