Le password devono essere ripristinate automaticamente quando cambia il metodo sottostante

95

Sono attualmente un ingegnere su un progetto in fase di sviluppo. Un "modulo" su questo progetto dà la possibilità per l'autenticazione / autorizzazione dell'utente. Tuttavia, ci viene in mente che l'algoritmo di hashing della password potrebbe non essere all'altezza di cop (ovvero non BCrypt). (La cosa terribile non è abbastanza sicuro di cosa sia e da dove viene!).

Questo ovviamente deve cambiare e la patch è in programma. Dobbiamo aggiornare naturalmente tutti i nostri utenti di test perché le loro password utilizzeranno il vecchio metodo di hashing, non un grosso problema, tutti i nostri utenti demo sono automatizzati su build, quindi sta aggiornando lo script. Ma la prossima domanda è se questo è un sistema di produzione con utenti attivi e stantii, di tutte le quantità. Quale sarebbe la migliore pratica.

  1. forzare automaticamente la reimpostazione della password su ogni utente? Ciò notificherà ad ogni utente che la sua password è stata cambiata e potrebbe causare domande / confusione e potrebbe causare il sospetto di una violazione della sicurezza. Possono essere poste più domande a cui potrebbe non essere possibile rispondere necessariamente dagli stakeholder del sito Web.
  2. Aggiorna il DB per segnalare se si tratta del nuovo o del vecchio metodo, quindi una volta che un utente è stato autenticato, aggiorna la password nel DB utilizzando. Richiede un po 'di logica nel servizio e la transizione apparirà imprevedibile a 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 uno meno sicuro risulta essere insicuro, potrebbe ovviamente essere rotto.
  3. Reimposta tutte le password, utilizzando una versione BCrypted dell'hash esistente. Contrassegnalo come vecchio stile, quindi con un'autenticazione corretta mantiene solo un hash della password piuttosto che un hash di un hash.
posta Crazy Dino 21.03.2016 - 15:03
fonte

6 risposte

90

L'opzione 1. è una cattiva idea: oltre alle motivazioni Esperienza utente / Pubbliche relazioni, dichiari anche agli attaccanti una finestra per intercettare i token di reimpostazione della password e compromettere ogni account sul tuo server. Inoltre, non risolve il problema se hai un solo utente troppo pigro per accedere / aggiornare la password.

A prima vista, sia il 2. che il 3. mi sembrano a posto. Il tuo n. 2 non è meno sicuro di quello che stai facendo ora, ma 2. significherebbe che devi continuare a sostenere l'accesso debole corrente per sempre (o fare qualcosa del tipo "Dopo X mesi stiamo cancellando la tua password e costringendoti a fare un recupero "che interrompe la buona trasparenza dell'utente che vuoi, quindi ignoriamolo).

Consideriamo il caso in cui si hanno utenti nel DB che non si collegheranno mai più. Con entrambe le versioni 2. e 3. devi continuare a supportare l'algoritmo di hashing corrente nel tuo codice base per sempre solo nel caso in cui accedono, ma almeno 3. ha il vantaggio che loro (o meglio, tu) sono protetti contro attacchi brute-force offline se il tuo DB viene mai rubato.

Dato che dovrai mantenere invariata la colonna "vecchio stile" per sempre, fai un favore e rendi un int non un bool in modo che se dovessi aggiornare di nuovo l'hashing della password alg, puoi registrare quale vecchio stile su cui si trovano.

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

    
risposta data 21.03.2016 - 15:14
fonte
14

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

  1. Configura il tuo nuovo sistema di password come faresti se avessi iniziato oggi.
  2. Crea una nuova tabella separata con campi per username (o id), algoritmo di hashing (nome o id), salt.
  3. Al login, controlla se l'utente ha un record nella tabella separata e, in tal caso, cancella la password alla vecchia maniera, quindi esegui l'hash del risultato in un modo nuovo e confronta con l'hash di bcrypt. Se corrisponde, re-salla / elimina la password nel nuovo modo ed elimina il record dalla tabella separata.

Il rovescio della medaglia è che dovrai mantenere la password in memoria per alcuni millisecondi (chi se ne frega) e avrai la ricerca extra di tabelle su ogni accesso, praticamente per sempre, finché la tabella separata non sarà vuota o fino a quando i vecchi account diventano obsoleti abbastanza da richiedere loro di reimpostare loro la password.

    
risposta data 21.03.2016 - 16:10
fonte
3

Tieni presente che, se il tuo schema OLD è sottoposto a hash con sale, non potrai utilizzare lo schema n. 3, a meno che non salvi SEPARATAMENTE il sale.

Normalmente il sale viene memorizzato insieme all'hash e tu usi il sale come input per la funzione hash - se non usi esattamente lo stesso sale, otterrai un output completamente diverso.

Se hai newhash (oldsalt + oldhash, newsalt), quindi, pur avendo la password corretta, non sarai in grado di ricreare oldhash (dato che non hai oldsalt), e non puoi generare l'hash finale. La stessa cosa vale per tutto ciò che ha parametri (ad esempio, bcrypt ha un parametro "costo", che deve essere impostato durante la crittografia e incorporato nell'output, da utilizzare durante la convalida della password).

ANCHE : come menzionato da altri, se stai memorizzando che l'hash è "vecchio" o "nuovo", 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 è quello di avere un segnalino 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 aver bisogno di creare il tuo prefisso per contrassegnarlo, oppure potresti riuscire a farla franca con "qualsiasi cosa che non inizi con" $ "è il vecchio algoritmo.

E infine, dal momento che ovviamente sei preoccupato (giustamente!) della sicurezza delle vecchie password, ti suggerirei di obbligare tutti a cambiare la loro password, inviando loro un'email con un token (NON INVIARE UN LINK! non vuoi che i tuoi utenti facciano clic su un link! digli semplicemente di accedere al solito posto). Quindi, chiedere 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.

INFINE: 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 lontano nel futuro (una settimana? Dipende da quanto tempo i tuoi clienti prendono per rispondere). Successivamente, dovranno passare attraverso le procedure di "reimpostazione della password".

    
risposta data 22.03.2016 - 02:01
fonte
2

Non so quale sia lo 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 di simile in un vecchio sistema BSD quando il sistema cambiava da una codifica della password tradizionale a una più sicura. Il nuovo è iniziato con una sequenza di caratteri che non poteva esistere nello schema precedente, quindi ogni volta che un utente con una vecchia password ha effettuato l'accesso, la sua password di testo non crittografata è stata convalidata utilizzando il vecchio metodo e re-hashed 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 se ne accorgesse.

Questo sarebbe da qualche parte tra il secondo e il terzo metodo.

So che in un vero sistema web di produzione le cose ora possono essere molto peggiori, 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 è connesso per diversi mesi può aver dimenticato la sua password - o puoi dirgli che lo ha fatto ... Ciò significa che aspetterei un po ' più a lungo qui probabilmente 3 o 6 mesi e dopo tale tempo reimpostare tutte le password vecchio stile su un valore proibito costringendo l'utente a reimpostare la sua password alla prossima connessione ... attraverso la schermata password dimenticata .

Le cose belle qui sono:

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

Lo svantaggio è che ti costringe a implementare simultaneamente sia il metodo di autenticazione + un aggiornamento automatico di tutte le password di stile.

    
risposta data 22.03.2016 - 17:30
fonte
0

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 suonano come fanno il lavoro ma mancano della logica per gestire effettivamente tutti i possibili possibili input validi.

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 un punto di partenza nel codificarlo per i tuoi scopi.

link

$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 farei sarebbe il tuo # 2 con ciò che è stato menzionato con l'utilizzo di un int. Dalla lettura della documentazione su PASSWORD_DEFAULT potrebbe cambiare quando vengono trovati algoritmi migliori e devono rimuovere quello corrente per motivi di sicurezza in caso di aggiornamento di php.

    
risposta data 22.03.2016 - 00:07
fonte
-1

Informare gli utenti in merito ai difetti di sicurezza nel vecchio sistema di autenticazione e suggerire che cambino / reimpostino la propria password per poter utilizzare il nuovo sistema di autenticazione. Se dopo un periodo di tempo prestabilito (che gli utenti possono essere avvisati nella "piccola stampa" da qualche parte) alcuni utenti non hanno ancora cambiato / resettato la loro password, disattivano il loro account e inviano loro una e-mail che li istruisce su come attivalo di nuovo. In questo modo, i tuoi utenti abituali si sentiranno come "chiesti" di cambiare la loro password, non "detto" di cambiare la loro password, quindi è improbabile che reagiscano negativamente alla richiesta anche se cambiano la loro password (che si spera che lo faranno , se la tua e-mail di consulenza è abbastanza convincente) e non dovrai supportare il vecchio sistema di autenticazione per sempre per i pochi utenti che non hanno mai avuto il tempo di cambiare la loro password.

    
risposta data 21.03.2016 - 17:01
fonte

Leggi altre domande sui tag