Autentica l'utente senza conoscere la sua password

1

Sto lavorando a un progetto in cui ogni utente avrà una coppia di chiavi RSA pubblica / privata. Gli utenti saranno in grado di inviare messaggi crittografati l'un l'altro utilizzando la chiave pubblica di ciascun utente di destinazione in modo che solo gli utenti target possano leggere il messaggio (simile a PHP openssl_seal ). Poiché desideriamo che l'utente sia in grado di utilizzare qualsiasi dispositivo per leggere o inviare un messaggio, la coppia di chiavi verrà memorizzata su un server API e la chiave privata verrà crittografata con la password dell'utente .

Quando un utente effettua l'accesso da un nuovo dispositivo, utilizzerà la sua password per decrittografare la chiave privata. Il problema è che idealmente, il server API non dovrebbe mai essere in grado di decifrare la chiave privata dell'utente, anche per autenticare l'utente . Inizialmente, stavo per inviare al client la chiave privata crittografata e lasciare che il client la decifrasse. Se il client può decrittografarlo, devono avere la password corretta, ma questo sarebbe vulnerabile agli attacchi del dizionario offline. Per evitare ciò, ho bisogno di autenticare l'utente prima io do loro la chiave privata crittografata.

Potrei chiedere al client di inviare la password al server e lasciare che il server tenti di decrittografare la chiave usando la password o anche solo di convalidare la password con un hash, ma in quel momento il server avrebbe temporaneamente la password e sarebbe in grado di decifrare la chiave privata dell'utente. Va bene, ma preferirei capire un modo per autenticare l'utente senza che il server conosca la loro password.

Nel mio caso, il client sarà un server web PHP o un'app mobile o desktop nativa, non un browser, quindi ho accesso a una vasta gamma di metodi crittografici. L'unico client autorizzato a effettuare la chiamata al server API per creare un account sarà il server Web PHP e al momento sto pianificando di creare una coppia di chiavi pubblica / privata e crittografare la chiave privata con la password dell'utente. Quindi invierà tali informazioni al server API (anch'esso in esecuzione PHP) per creare l'account. Il server API memorizzerà la chiave privata crittografata, la chiave pubblica, le informazioni sull'utente e tutti i messaggi crittografati, ma non sarà in grado di decodificarne nessuno.

Non sto cercando di proteggere da un attacco MITM qui. Tutte le chiamate API saranno su HTTPS. Il mio obiettivo è creare l'API in modo tale che, anche se il governo cinese potesse accedere al server API, non è ancora possibile leggere nessuno dei messaggi. Il server web può avere temporaneamente la chiave privata, non solo il server API.

Come faccio a consentire al server API di autenticare l'utente senza essere vulnerabile a un attacco brute-force offline e senza il server API che richiede la password dell'utente?

Sentitevi liberi di dirmi che sto facendo qualcosa di completamente sbagliato e suggerire qualcosa di completamente diverso.

    
posta Joshua Dwire 04.12.2013 - 17:21
fonte

5 risposte

3

Esegui il modo in cui MEGA lo fa: esegue la decifratura della crittografia all'interno del tuo browser utilizzando JavaScript. Consenti solo ai file crittografati di essere inviati al server (a meno che, ovviamente, le chiavi pubbliche).

Non avresti bisogno di inviare la chiave privata in qualsiasi punto al server (perché tutto viene fatto lato browser). Un piccolo avvertimento però, se il tuo utente perde una password o un file crittografato va corrotto, allora sei praticamente fregato e tutti i messaggi saranno inutili dato che non hai più la chiave.

Per autenticare l'utente è possibile utilizzare qualcosa come Open OpenID. L'utente dovrebbe comunque fornire una password per decrittografare la sua chiave privata, ma in nessun momento la chiave decodificata della password viene inviata al server (tutto rimane all'interno del browser).

    
risposta data 04.12.2013 - 17:41
fonte
3

PBKDF2 - Ciò ti consentirà di verificare che l'utente abbia la password, senza averlo inviato la password. Sul lato server, non si salva la password, ma si salva un hash della password.

    
risposta data 05.12.2013 - 16:30
fonte
2

Questo design soffre di un paradosso "promessa di non picco" ed è molto simile ai problemi di sicurezza LavaBit aveva , MEGA ha anche questo problema.

Per verificare che un utente abbia le credenziali di autenticazione corrette è necessario un sistema centralizzato per verificare queste credenziali. Questo sistema centralizzato può essere modificato da un utente malintenzionato per registrare le credenziali di autenticazione. .

MITM è il problema e questo attacco è usato dai governi. Un'app che registra tutte le password ha lo stesso effetto e potrebbe essere introdotta da un utente malintenzionato.

    
risposta data 04.12.2013 - 18:59
fonte
2

Perché non utilizzare solo un metodo di autenticazione basato su token esistente come Kerberos e crearne uno?

Quindi l'utente si autentica normalmente e riceve un token Kerberos. Quindi, vai al server API, dì "Ehi, ho preso questo token!" Il server API lo verifica e invia una copia dei dati crittografati all'utente, che può decrittografare le chiavi sul proprio computer?

Sembra abbastanza semplice.

    
risposta data 09.10.2014 - 17:47
fonte
1

Si sta dicendo che la chiave privata non può essere decodificata lato server per l'autenticazione (perché quindi il server avrebbe bisogno della password), e inoltre non può essere inviata a nessuno che la richieda, e quindi decifrata lato client (perché poi il la chiave privata sarebbe vulnerabile a un attacco di forza bruta offline.

In sostanza, ciò che rimane è progettare un meccanismo di password completamente separato e memorizzare qualche forma della password (ovviamente hashed / salted ecc.) sul server indipendentemente dalla chiave privata. Il grande svantaggio è che questo raddoppia la superficie di attacco della tua chiave privata: un utente malintenzionato può accedere alla chiave privata o cracciandola direttamente o irrompendo in tale database di password.

C'è un approccio completamente diverso. Invece di avere una coppia di chiavi per utente, avere una coppia di chiavi per dispositivo. Credo che Apple lo usi per iCloud. Quando un utente connette un nuovo dispositivo, viene generata una coppia di chiavi completamente nuova. Ciò ovvia alla necessità che la chiave privata lasci il dispositivo. La parte difficile - e quella che non comprendo appieno - è il modo in cui le coppie di chiavi di diversi dispositivi interagiscono tra loro.

Aggiornamento:

Apple ha alcune informazioni su come funziona. Guarda la sezione per il portachiavi iCloud. Non è un dettaglio tecnico, ma abbastanza per avventurarmi in un paio di ipotesi aggiuntive.

Con questo schema, non utilizzeresti la password per crittografare le chiavi (il che è un vantaggio importante perché le password sono sempre la parte più debole della crittografia).

Ecco come potrebbe applicarsi alla tua situazione:

  • Ogni dispositivo del tuo servizio riceve la propria coppia di chiavi quando l'utente lo registra. Ciò avverrebbe in modo trasparente; la chiave privata non arriverà mai al tuo server (né crittografata né non crittografata).

  • Ogni account utente ha una chiave di crittografia master (simmetrica, non chiave pubblica) che viene effettivamente utilizzata per crittografare il contenuto. Apple utilizza apparentemente AES128.

All'iscrizione iniziale per il primo dispositivo:

  • Il dispositivo genera una coppia di chiavi e invia la chiave pubblica al server.

  • Il server genera la chiave master, la crittografa utilizzando la chiave pubblica e memorizza la chiave master crittografata nel record del dispositivo del database. Questa è l'unica volta in cui il server ha la chiave master in forma non crittografata.

Quando accedi al tuo servizio:

  • L'utente accede al tuo servizio utilizzando il nome utente / password.

  • Il dispositivo recupera la chiave di crittografia master che è stata crittografata utilizzando la propria chiave pubblica.

  • Il dispositivo decodifica localmente la chiave di crittografia master e la utilizza per accedere al contenuto sul server.

Quando aggiungi un nuovo dispositivo, l'utente ha bisogno di un dispositivo già registrato (dispositivo A) e, naturalmente, del nuovo dispositivo (dispositivo B)

  • L'utente utilizza il dispositivo B per registrarsi al servizio. Questo genererà un'altra coppia di chiavi. Potresti aver bisogno di nome utente e password per farlo.

  • il dispositivo B invia la chiave pubblica al server.

  • L'utente accede utilizzando il dispositivo A e "autorizza" il dispositivo B.

  • dispositivo A recupera la chiave principale con la chiave pubblica del dispositivo A.

  • dispositivo A recupera la chiave pubblica del dispositivo B.

  • dispositivo A decrittografa la chiave master utilizzando la propria chiave privata, quindi ricodifica la chiave master utilizzando la chiave pubblica del dispositivo B.

  • dispositivo carica la chiave master crittografata con la chiave pubblica del dispositivo B sul server.

A questo punto, il server ha due copie della stessa chiave master simmetrica: una crittografata con la chiave pubblica del dispositivo A, una con la chiave pubblica del dispositivo B.

Ora il dispositivo A e il dispositivo B possono entrambi accedere al contenuto utilizzando la stessa chiave master.

Apple apparentemente consente anche di memorizzare la chiave di crittografia master non crittografata sul proprio server per consentire il ripristino delle chiavi in caso di perdita di tutti i dispositivi. Questo ovviamente mina il tuo obiettivo dichiarato.

Ovviamente, questo approccio è vulnerabile ad almeno due attacchi:

  • Un'applicazione client dannosa può esfiltrare la chiave master non crittografata.
  • Un server compromesso può memorizzare la chiave master mentre viene generata. È possibile impedirlo creando la chiave master lato client sul client iniziale.

Un'altra cattura: questo metodo potrebbe essere soggetto a un brevetto.

    
risposta data 06.04.2015 - 01:02
fonte

Leggi altre domande sui tag