it-swarm-eu.dev

Le password devono essere ripristinate automaticamente quando cambia il metodo sottostante

Attualmente sono un ingegnere di un progetto in fase di sviluppo. Un "modulo" su questo progetto offre la possibilità di autenticazione/autorizzazione dell'utente. Tuttavia, ci preoccupiamo che l'algoritmo di hashing delle password potrebbe non essere all'altezza della situazione (alias non BCrypt). (La cosa terribile non è del tutto sicura di cosa sia e da dove venga!).

Questo ovviamente deve cambiare e la patch è in programma. Dobbiamo aggiornare naturalmente tutti i nostri utenti di test perché le loro password useranno il vecchio metodo di hashing, non è un grosso problema, tutti i nostri utenti demo sono automatizzati sulla build, quindi aggiorna lo script. Ma la domanda successiva è se questo è un sistema di produzione con utenti attivi e non aggiornati, di tutti gli importi. Quale sarebbe la migliore pratica.

  1. Forzare automaticamente una reimpostazione della password su ogni utente? Questo avviserà ogni utente che la sua password è stata modificata e può causare domande/confusione e può sospettare che vi sia stata una violazione della sicurezza. È possibile che vengano poste ulteriori domande a cui potrebbe non essere possibile rispondere dagli stakeholder del sito Web.
  2. Aggiorna il DB per contrassegnare se si tratta del metodo nuovo o precedente, quindi una volta che un utente è stato autenticato aggiorna la sua password nel DB utilizzando. Richiede un po 'di logica nel servizio e la transizione sarà assurda per qualsiasi utente esistente. Il problema è che se ci fosse una violazione, allora potrebbe essere evidente che ci sono due metodi in corso qui e se si scopre che uno meno sicuro è così insicuro, potrebbe ovviamente essere rotto.
  3. Reimposta tutte le password, utilizzando una versione BCrypted dell'hash esistente. Contrassegnalo come un vecchio stile, quindi con un'autenticazione corretta mantiene solo un hash della password anziché un hash di un hash.
94
Crazy Dino

La tua opzione 1. è una cattiva idea: oltre ai motivi di User Experience/Public Relations che dichiari, stai anche dando una finestra agli aggressori per intercettare i token di reimpostazione della password e compromettere ogni account sul tuo server. Inoltre, non risolve il problema se hai anche un utente che è troppo pigro per accedere/aggiornare la propria password.

A prima vista, sia 2. che 3. mi sembrano a posto. Il tuo # 2 non è meno sicuro di quello che stai facendo ora, ma 2. significherebbe che devi continuare a supportare l'attuale accesso debole per sempre (o fare qualcosa del tipo "Dopo X mesi stiamo cancellando la tua password e ti costringiamo a fare un recupero "che rompe la trasparenza dell'utente di Nizza che desideri, quindi ignoriamola).

Consideriamo il caso in cui ci siano utenti nel DB che non accederanno mai più. Con entrambi 2. e 3. devi continuare a supportare l'attuale hash alg nella tua base di codice per sempre nel caso in cui effettuino il login, ma almeno 3. ha il vantaggio che essi (o meglio, tu) sono protetti contro attacchi di forza bruta offline se il tuo DB viene mai rubato.

Dato che dovrai mantenere la colonna "old style flag" per sempre, fatti un favore e rendila un int non un bool in modo che se dovessi mai aggiornare l'hash della password ancora una volta, puoi registrare su quale stile vecchio sono su.


AGGIORNAMENTO: è stata posta una domanda molto simile qui e costruita sulla discussione di questo thread.

89
Mike Ounsworth

Se riesci a fare l'opzione 3, non vedo perché dovresti anche considerare gli altri. È di gran lunga l'opzione migliore. Con questa opzione, la mia sensazione sarebbe quella di considerare l'utilizzo di due diversi sali, uno per il vecchio algoritmo e uno per quello nuovo con bcrypt. Sto immaginando un set come questo:

  1. Imposta il tuo nuovo sistema di password come faresti se stessi iniziando oggi.
  2. Creare una nuova tabella separata con campi per nome utente (o ID), algoritmo di hashing (nome o ID), salt.
  3. All'accesso, controlla se l'utente ha un record nella tabella separata e, in tal caso, esegui l'hashing della password alla vecchia maniera, quindi esegui l'hash del risultato in modo nuovo e confrontalo con l'hash bcrypt. Se corrisponde, re-salt/hash la password nel nuovo modo ed eliminare il record dalla tabella separata.

Il rovescio della medaglia è che dovrai mantenere la password in memoria qualche millisecondo in più (chi se ne frega) e avrai la ricerca della tabella extra su ogni accesso, praticamente per sempre, fino a quando la tabella separata non sarà vuota o fino a quando i vecchi account diventeranno abbastanza stantio che sei disposto a richiedere loro di reimpostare la password da soli.

14
TTT

Nota che, se il tuo VECCHIO schema è sottoposto a hash con il sale, non sarai in grado di usare lo schema n. 3, a meno che non conservi il sale SEPARATAMENTE.

Normalmente il sale viene memorizzato insieme all'hash e si utilizza il sale come input per la funzione hash: se non si utilizza esattamente lo stesso sale, si otterrà un output completamente diverso.

Se newhash (oldsalt + oldhash, newsalt), quindi, pur avendo la password corretta, non sarai in grado di ricreare oldhash (poiché non hai oldsalt) e non puoi generare l'hash finale. La stessa cosa vale per tutto ciò che ha parametri (ad es. Bcrypt ha un parametro "cost" - questo deve essere impostato durante la crittografia ed è incorporato nell'output, per l'uso durante la convalida della password).

ANCHE : come è stato detto da altri, se stai memorizzando che l'hash è "vecchio" o "nuovo" stile, considera invece di memorizzare lo "schema" - dove, ad es 0 è il "vecchio" e 1 è bcrypt (nota che non uso "nuovo" - è "nuovo" ora, non sarà "nuovo" per sempre!). Un modo comune per farlo è avere un marcatore all'inizio dell'hash (questo potrebbe già essere il caso!). bcrypt utilizza uno dei seguenti prefissi standard: "$ 2a $", "$ 2b $", "$ 2x" o "$ 2y $". A seconda dei possibili output del tuo "vecchio" algoritmo, potresti dover creare il tuo prefisso per contrassegnarli, oppure potresti riuscire a cavartela con "tutto ciò che non inizia con" $ "è il vecchio algoritmo.

E infine, poiché ovviamente sei preoccupato (giustamente!) Della sicurezza delle vecchie password, suggerirei di costringere tutti a cambiare la loro password, inviando loro istruzioni via e-mail con un token (NON! INVIARE UN LINK! Non vuoi i tuoi utenti che fanno clic su un link. Dì loro di accedere al solito posto). Quindi, chiedi il token E la loro password. Altrimenti, qualcuno che ha rubato una password in passato può cambiare la password e ottenere una "nuova" password valida.

FINALMENTE: avere una data di scadenza - se le password non vengono modificate entro questa data, dovrebbero essere invalidate. Questa data dovrebbe essere nell'e-mail e non troppo in futuro (una settimana? Dipende da quanto tempo impiegano i tuoi clienti a rispondere). Successivamente, dovranno passare attraverso le procedure di "reimpostazione della password".

3
AMADANON Inc.

Non so quale sia il tuo schema di codifica della password, ma se non è così male, è probabile che la struttura della password nel vecchio e nel nuovo formato sia diversa.

Ho già visto qualcosa del genere in un vecchio sistema BSD quando il sistema è passato da una tradizionale codifica password a una più sicura. Il nuovo è iniziato con una sequenza di caratteri che non poteva esistere nel vecchio schema, quindi ogni volta che un utente con una vecchia password ha effettuato l'accesso, la sua password in chiaro è stata convalidata utilizzando il vecchio metodo e silenziosamente rielaborata e archiviata nuovamente nel database delle password con il nuovo metodo. Dopo un mese, nessuna vecchia password era presente nel database, senza che l'utente finale notasse nulla.

Sarebbe da qualche parte tra il secondo e il terzo metodo.

So che in un vero sistema Web di produzione, ora le cose possono andare molto peggio, perché gli utenti possono aspettare settimane o addirittura mesi prima di riconnettersi. Ma (a seconda dell'attività reale) può essere mitigato dal fatto che un utente che non si connette da diversi mesi può aver dimenticato la sua password - oppure puoi dirgli che lo ha fatto ... Ciò significa che aspetterei un po ' più a lungo qui probabilmente 3 o 6 mesi e dopo quel tempo reimposterei tutte le password di vecchio stile su un valore proibito costringendo l'utente a reimpostare la sua password sulla connessione successiva ... attraverso la schermata password dimenticata.

Le cose belle qui sono:

  • trasparente per utenti regolari
  • nessuna modifica dello schema del database - a condizione che il campo password possa accettare entrambi gli stili
  • gli utenti occasionali verranno semplicemente gestiti come se avessero dimenticato la password dopo mesi senza usarla

Il rovescio della medaglia è che ti costringe a implementare contemporaneamente sia il metodo di autenticazione + un aggiornamento automatico di tutta la password di stile.

2
Serge Ballesta

Non hai menzionato la lingua che stai utilizzando. Php ha i suoi problemi con varie funzioni che dovrebbero restituire false quando dovrebbe restituire true in alcuni casi, o altre funzioni che sembrano fare il lavoro ma mancano della logica per gestire effettivamente tutti gli input possibili validi possibili.

Ma questo è il modo corretto di fare ciò di cui stai parlando in php anche se non stai usando php. Il codice di alto livello può lasciarti con un punto di partenza per codificarlo per i tuoi scopi.

http://php.net/manual/en/function.password-needs-rehash.php

$password = 'rasmuslerdorf';
$hash = '$2y$10$YCFsG6elYca568hBi2pZ0.3LDL5wjgxct1N8w/oLR/jfHsiQwCqTS';

// The cost parameter can change over time as hardware improves
$options = array('cost' => 11);

// Verify stored hash against plain-text password
if (password_verify($password, $hash)) {
    // Check if a newer hashing algorithm is available
    // or the cost has changed
    if (password_needs_rehash($hash, PASSWORD_DEFAULT, $options)) {
        // If so, create a new hash, and replace the old one
        $newHash = password_hash($password, PASSWORD_DEFAULT, $options);
    }

    // Log user in
}

Quello che vorrei fare sarebbe il tuo numero 2 con ciò che è stato menzionato usando un an int. Dalla lettura della documentazione su PASSWORD_DEFAULT potrebbe cambiare quando vengono trovati algoritmi migliori e devono rimuovere quello attuale per motivi di insicurezza man mano che php viene aggiornato.

0
Eric