Cambio funzione hash

26

Ho le password degli account utente memorizzate in un database utilizzando una funzione hash crittografica non sicura (precedente).

Qual è l'approccio migliore / abituale alla modifica della funzione hash della password? Mi vengono in mente solo due idee:

  1. Chiedere a tutti gli utenti di cambiare le loro password al prossimo accesso e cancellare le loro password con una nuova funzione quando lo fanno. Questa non è una buona opzione a causa di molti problemi (utenti non attivi, lunghi periodi di migrazione, implementazione complicata ...)

  2. Hash i vecchi valori hash con la nuova funzione hash e riscrivi il metodo per controllare le password rispetto al database: newHash (salt + oldHash (salt + password))

Questo doppio hashing mi sembra una buona idea, sia elegante che semplice da implementare.

Vorrei sapere se ci sono dei avvertimenti che non sto notando qui. È questo il modo in cui di solito viene fatto o esiste un altro metodo? Esiste qualche vulnerabilità crittografica nota nell'uso dell'output della funzione hash debole come input della funzione hash strong.

Se è una buona idea, per quanto riguarda il sale? Andrebbe bene usare lo stesso sale per entrambe le funzioni hash?

    
posta h9lpq0u 27.08.2012 - 16:01
fonte

6 risposte

17

Personalmente, probabilmente implementerei sia con i nuovi utenti che ottengono un hash moderno strong (bcrypt o altro hash crittografico rinforzato con chiave), sia i vecchi utenti con l'hash debole avvolti attorno a bcrypt. Prima che le persone si lamentino di una complessità di implementazione extra, l'alternativa è di forzare sempre i nuovi utenti a utilizzare un algoritmo di hash debole avvolto attorno a un strong algoritmo di hash, e ciò significa che non si eliminerà mai lo schema originale.

Avrei qualche indicatore documentato dello schema di hash del tipo analogo a $1$ , $2a$ , $5$ o $6$ in crypt (citazione dalla pagina man crypt):

   If  salt is a character string starting with the characters "$id$" fol‐
   lowed by a string terminated by "$":

          $id$salt$encrypted

   ... id  identifies  the  encryption
   method  used  and  this  then  determines  how the rest of the password
   string is interpreted.  The following values of id are supported:

          ID  | Method
          ─────────────────────────────────────────────────────────
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

In questo caso, hai bisogno di tre tipi di hash password:

  1. I vecchi hash fast weak
  2. I vecchi hash veloci e deboli racchiusi in un hash lento con un strong sale
  3. Il nuovo hash lento.

Il giorno 1, prenderei tutto dalla categoria 1 e lo sposterei nella categoria 2. Le nuove password verrebbero inserite nella categoria 3. Inoltre, quando le persone accedono, puoi persino migrare ogni hash autenticato correttamente dalla categoria 2 alla categoria 3 mentre la password in chiaro è in memoria. Ad un certo punto, puoi persino eliminare completamente qualsiasi prova / mantenimento legacy del debole schema di hashing. (Es. Forzare gli utenti con account che non hanno effettuato l'accesso per almeno 2 anni dopo la modifica per reimpostare le proprie password).

    
risposta data 27.08.2012 - 16:40
fonte
10

La tua proposta 2 (prendi il vecchio valore hash come "password" per il nuovo hash) è buona se le seguenti condizioni sono tutte vere:

  • Il vecchio hash è sufficientemente resistente alle pre-immagini .
  • Il nuovo hash utilizza tutti i necessari suoni di campana per considerarlo "robusto" (vale a dire bcrypt con un molti round e un nuovo salt random per ogni password, incluse le modifiche della password per un determinato utente.
  • Il vecchio hash può essere calcolato in modo sufficientemente efficiente che l'intera attività della "lentezza configurabile" si basa esclusivamente sul nuovo hash.

Nota che MD5, sebbene completamente rotto per quanto riguarda le collisioni, sembra ancora abbastanza strong per quanto riguarda le pre-immagini.

Sarebbe comunque utile per i tuoi interessi includere un campo "tipo di hash" nel tuo database, in modo che le migrazioni possano essere gestite senza intoppi. Ad esempio, è possibile applicare il proprio hash-of-hash e quindi pianificare una migrazione a uno schema di hashing delle password che utilizza solo il nuovo hash - le password verranno aggiornate al nuovo schema ogni volta che vengono create o modificate, per un migrazione graduale. In seguito (diciamo tra un anno), potresti impostare un aggiornamento forzato (l'utente deve reinserire la password al prossimo accesso) per le password che usano ancora il vecchio formato.

Anche se non ti piacciono le migrazioni (chi lo fa?), sembra prudente prevedere una possibile migrazione futura, se le condizioni in quel momento impongono la migrazione su di te (ad esempio una devastante interruzione crittanalitica).

    
risposta data 27.08.2012 - 17:38
fonte
7

Vorrei usare bcrypt come nuovo hash. Altrimenti, la tua soluzione di "fasciare" i vecchi hash dovrebbe essere sicura, dato che usi un buon sale per bcrypt. Ho visto questa soluzione funzionare bene un paio di volte quando i sistemi vogliono aggiornare il modo in cui hanno cancellato le loro password.

    
risposta data 27.08.2012 - 16:13
fonte
6

Se non vuoi preoccuparti di usare la vecchia funzione di hash, ma non vuoi forzare tutti a cambiare la tua password, c'è una soluzione elegante.

Aggiungi una colonna / valore a ogni profilo utente. Chiamiamo se HashVersion

Quando l'utente accede per la prima volta dalla migrazione, il sistema sarà in grado di rilevare che sta utilizzando la vecchia funzione di hash. Quindi, se la password fornita dall'utente corrisponde al tuo hash, allora prendi la password in testo semplice e la cancella con il tuo nuovo algoritmo, ripristinando i sali e così via. E poi fai un salto su HashVersion così sai che ora sta usando la nuova funzione di hash.

Questa è, a mio parere, la soluzione migliore, specialmente se la tua precedente funzione di hash era davvero insicura.

    
risposta data 27.08.2012 - 19:49
fonte
2

Finché il vecchio hash è decente (MD5 o DES-Crypt va bene, CRC32 non lo è) questo approccio è sicuro. L'uso dello stesso sale non dovrebbe portare a problemi, presumendo che il sale sia abbastanza buono (quasi) globalmente unico.

Per la funzione di hashing esterno, ti consiglio di utilizzare uno di scrypt, bcrypt o PBKDF2.

    
risposta data 27.08.2012 - 16:09
fonte
1

Troverai dozzine di applicazioni open source che hanno risolto questo problema. Wordpress viene subito in mente, ma ce ne sono anche altri. Anche Microsoft Windows usa questa stessa tecnica. La soluzione generale è questa:

  • L'output di ciascuna funzione di hash supportata viene prontamente distinto; o controllando il formato di output o la lunghezza, o (più appropriatamente) anteponendo una stringa di identificatore (ad esempio sha1:salt:_hash_output____ ) o aggiungendo un nuovo campo al database per identificare il tipo di hash.
  • Continui a supportare l'autenticazione tramite tutte le funzioni di hash utilizzate in precedenza, ma tutti i nuovi hash mostreranno solo la versione preferita.
  • Facoltativamente, se un utente viene autenticato utilizzando una versione di hash precedente, la password autenticata verrà re-hash utilizzando l'algoritmo preferito e l'hash memorizzato verrà aggiornato.
risposta data 28.08.2012 - 05:13
fonte

Leggi altre domande sui tag