Posso utilizzare l'hash della password di un utente come chiave AES per creare un token una tantum?

4

Voglio creare un token una tantum che gli utenti utilizzano per reimpostare la propria password. Il token deve essere invalidato una volta utilizzato, è sicuro utilizzare la password attualmente hash come chiave AES per crittografare il token in modo che, una volta modificata la password, il token non possa più essere decodificato? Questo token sarà crittografato / decodificato solo sul server.

Quali sono i lati negativi / aspetti positivi di questo approccio?

    
posta JF6IX 17.12.2018 - 23:43
fonte

4 risposte

2

Il problema che si verifica è che se l'hash della password è tutto ciò che è necessario per generare un token valido, un utente malintenzionato con un dump del database può generare token di reimpostazione per tutti (che tipo di sconfigge lo scopo delle password di hashing in primo luogo ). Questo problema può essere risolto, ma finisce per essere molto più complicato dell'uso di valori casuali per resettare i token e archiviare i loro hash in una tabella.

Nota importante: non lo implementerei da solo senza ulteriori verifiche, mi sono appena inventato per la maggior parte del tempo. Dare agli altri la possibilità di sottolineare cosa ho sbagliato. Seriamente, l'ho già rovinato una volta.

Quali proprietà richiede un token di reimpostazione della password?

  1. Identifica un utente specifico ed è valido per nessun altro
  2. Non più valido dopo la modifica della password
  3. Scade dopo qualche tempo
  4. Segreto e molto difficile da indovinare
  5. Il dump del database non attribuisce a un utente malintenzionato alcun token esistente o consente loro di generare token a piacimento

Dato che vuoi avere i token di reimpostazione senza doverli memorizzare in un database, ti suggerirei questo psuedocode per la generazione:

token = {
    "user": [username],
    "expiry": [unix timestamp]
}

// Very important!!!
// Password hash should be bcrypt or argon2 with good cost
// Secret application "pepper" is used to salt the key with HKDF, so a database dump won't allow generating reset tokens
key = hkdfsha256(user_password_hash, pepper)

return base64encode(token + hmacsha256(token, key))

E per verificare:

data = base64decode(data)
token = data[:-32]
submitted_hmac = data[-32:] // last 32 bytes are hmacsha256
if (token['expiry'] > now()) {
    return false
}
// [retrieve password hash here]
key = hkdfsha256(user_password_hash, pepper)
return hmacsha256(token, key) == submitted_hmac

Esame

  1. Il nome utente identifica l'utente per cui il token è
  2. Derivare la chiave HMAC dall'hash della password significa che una volta che la password è stata modificata il token non è più valido
  3. Il controllo di scadenza impedisce a un token inutilizzato di rimanere valido per troppo tempo
  4. L'hash della password e il pepe rendono l'output HMAC (e quindi il token completo) non percettibile
  5. L'utilizzo di un pepe per derivare la chiave HMAC impedisce a un utente malintenzionato con un dump del database di generare token per tutti

Pro

  • Nessuna memoria di database
  • La validità del token è intrinsecamente legata alla password corrente
  • Tutti i token attualmente validi possono essere invalidati facilmente cambiando il pepe

Contro

  • Dimensioni token un po 'più grandi (108 caratteri base64 con nome utente di 15 caratteri), ma dovrebbe comunque essere ok per un URL in un messaggio di posta elettronica.
  • Il token non è completamente opaco, gli utenti possono vedere le informazioni su utente e scadenza. Questo non ha alcun effetto sulla sicurezza, ma se vuoi evitare fastidiose domande da parte di persone che pensano che sia un problema potresti crittografarlo, anche se questo significa aggiungere un IV (se lo fai devi cifrare prima em> HMAC).
  • Se un utente malintenzionato ottiene un dump del database e il pepe, può generare token a volontà.
  • Non c'è modo di sapere quanti token validi esistono in un dato momento o per quali utenti.

Alcuni pensieri

  • L'utilizzo dell'intero hash della password significa che il sale farà parte della chiave HMAC, quindi dovrebbe contenere già una grande quantità di entropia anche se la password è terribile e il pepe viene esposto. Per attaccare questo schema, sia il database pepper che dovrebbero essere esposti.
  • Se veramente vuoi rendere il token più piccolo, puoi troncare l'output HMAC a 16 byte, null terminare il nome utente e fare username + 5 byte unix timestamp + 16 byte HMAC . Ciò evita il problema 2038 con il timestamp e con un nome utente di 15 caratteri è di 52 caratteri base64. Non raccomanderei comunque di fare il timestamp a 5 byte, i 3 extra byte non sembrano valere la pena.
  • Poiché la quantità di spazio che stai salvando è strettamente inferiore alla tabella degli utenti che stai già archiviando, non credo che ne valga la pena. Forse se non sei stato in grado di modificare lo schema del database e non aveva già un modo per memorizzare un token di ripristino.
risposta data 18.12.2018 - 23:46
fonte
1

Uno svantaggio significativo è che non puoi limitarlo nel tempo.

Immagina che l'utente richieda un reset ma non lo usa mai quando ricorda la password. A questo punto c'è un token con una durata fino a quando la password cambia.

Sarebbe meglio generare un token univoco per tentativo di reset usando qualsiasi mezzo sicuro. Metti questo in una tabella di database separata con una scadenza.

Punti bonus per il monitoraggio se vengono utilizzati token di ripristino precedenti, poiché ciò potrebbe indicare un'attività sospetta (se combinata con altri segnali).

    
risposta data 18.12.2018 - 00:36
fonte
1

Ciò che descrivi non contiene una data di scadenza intrinseca - quindi continuerà a essere fattibile fino a quando la password (e / o il sale) non saranno cambiati. Ovviamente potresti incorporare una data di scadenza nel testo chiaro che stai crittografando insieme ad altri fatti interessanti sulla richiesta di ripristino.

Anche se è molto improbabile che sia la crittografia aes sia l'hashing della password vengano interrotti, dovrei passare un po 'di tempo a pensare se questo rischio molto piccolo sia stato superato dal vantaggio di usare questo come chiave del costo di generare una chiave in qualche altro modo (ad esempio una chiave casuale) e di memorizzarla / indicizzarla e, ovviamente, contrassegnarla come utilizzata / sostituita. La mia reazione istintiva iniziale era no, ma più ci penso, più elegante sembra ad es. non dovrebbe esserci alcun rischio di riempimento di un attacco Oracle se si utilizzano gli hash delle password decenti.

Assicurati di utilizzare l'hash della password e non gli altri dati memorizzati nell'attributo. Hai bisogno di una risposta da parte di qualcuno che conosce molto più sulla crittografia di me che sul fatto che sia necessario un vettore di inizializzazione, ma se il carico utile è inferiore o uguale alla dimensione del blocco di crittografia, io non pensa c'è qualche vantaggio. Tieni presente che, se ti aspetti che l'utente digiti il testo cifrato completo (non puoi troncarlo con testo in chiaro variabile), stai ancora guardando oltre 20 caratteri di parole senza senso (senza IV).

    
risposta data 18.12.2018 - 00:54
fonte
1

Questo è qualcosa per cui è stato inventato un sistema come PBKDF2 o RFC2898, in combinazione con il key wrapping. Sono progettati per prendere input dell'utente e restituire stringhe basate su hash forti che è possibile utilizzare così come per il controllo della password, ma anche per ulteriori operazioni come materiale chiave. Non è l'unica opzione e più (e diversi) sistemi per farlo vengono messi in uso per questo scenario.

Scopri la derivazione della chiave basata su password e il key wrapping per saperne di più. E come sempre con crypto: non eseguire il rollover , ma usa una libreria ben testata.

Per il tuo caso specifico (usa un token per reimpostare un account): esiste invece un caso contro la generazione di un token casuale? La ragione per usare qualcosa come AES sarebbe la crittografia reversibile usando la stessa chiave usata per crittografarlo, che non sembra subito un caso d'uso qui.

    
risposta data 18.12.2018 - 03:42
fonte

Leggi altre domande sui tag