Reimpostazione della password: ID utente e timestamp con firma crittografica o valore generato casualmente?

2

Quali sono i pro e i contro dei diversi modi di gestire i link di ripristino? Vedo due modi per gestirli:

  1. Genera una stringa casuale, ad esempio con uuid4. Memorizzalo nel database con l'utente e invialo in un link all'utente. Quando il modulo è compilato e inviato la stringa casuale sarà il carico utile e abbinato all'utente. La stringa viene quindi rimossa dal database in modo che possa essere utilizzata solo una volta. Dovrebbe anche avere una data di scadenza.
    • Pro:
      • Semplice e sicuro
    • Contro:
      • È necessario memorizzarlo nel database
      • Un utente malintenzionato può causare scritture di database ricorrendo ripetutamente alla funzione "password dimenticata". Questo dovrebbe essere mitigato da un numero massimo di gettoni al giorno e questo limita ancora solo per un account. Se il token viene sovrascritto, lo spazio di archiviazione non ha importanza, ma potrebbe comunque costare denaro sotto forma di scritture del database.
  2. Generazione di un token firmato. Dal nome utente o dall'ID e da un timestamp, un token firmato viene generato con una chiave segreta. Questo è il link inviato all'utente. Quando l'utente invia il token viene decrittografato e l'utente e il timestamp vengono recuperati e convalidati. Il problema qui è che può essere riutilizzato, quindi è necessario memorizzare anche la vecchia password nel collegamento (sarebbe un hash salato). Non mi piace l'idea di poterlo riutilizzare, e se fosse usato su un computer pubblico? Quindi l'utente deve cancellare la cronologia del browser, male!
    • Pro
      • Nulla deve essere memorizzato nel database.
    • Contro
      • più rischiosi? È una cattiva idea inviare la vecchia password crittografata (hash salata) nel link? Se "ultima modifica" è già stata memorizzata, è possibile inviarla invece senza scrivere nel database alla richiesta di ripristino.
posta Testare1 Testsson 06.01.2017 - 20:47
fonte

6 risposte

2

Mi piacerebbe andare all'opzione 1 fino in fondo - vuoi assicurarti che un determinato token sia usato una volta sola e non è possibile farlo senza una voce del database.

    
risposta data 06.01.2017 - 21:22
fonte
2

Ciascuno è valido, a condizione che il valore casuale sia sufficientemente casuale e che la crittografia / la firma utilizzi algoritmi appropriatamente forti. Hai già iniziato a pensare a specifici scenari di problemi: ti incoraggerei a continuare.

Se assumiamo che ci sia il rischio che i valori siano prevedibili (o possibili alla forza bruta) o qualche altra vulnerabilità (limitata) sul sito, allora il valore casuale ha qualche vantaggio. Poiché è memorizzato sul lato server, serve anche a segnalare che l'account è in uno stato modificabile. Gli exploit che prendono di mira il processo di rinnovo saranno efficaci solo contro quella che dovrebbe essere una piccola parte dei conti. Tuttavia questo è davvero un caso limite.

Un problema che ho riscontrato con il valore casuale è questo: non riesco a ricordare la mia password, clicco sul pulsante di reset, aspetto, non ho email, quindi clicco nuovamente sul link. Quando arriva l'email di reset, non funziona! (perché è dal primo reset, e una seconda email è in arrivo con il codice corrente). OTOH per bloccare un secondo tentativo di reset di un eccesso di confidenza. Forse una soluzione pragmatica è un periodo refrattario dopo l'ultimo reset in cui non è possibile eseguire un ulteriore reset.

Un'ulteriore considerazione è che probabilmente potrei sopportare la trascrizione di un UUID dal mio dispositivo di messaggistica al mio dispositivo di navigazione (se per qualche motivo non potrei o non volessi tagliare e incollare tra loro e non potrei cliccare attraverso il dispositivo di messaggistica) ma un messaggio cifrato e firmato sarà molto, MOLTO più lungo.

Riguardo al problema del computer pubblico - non credo che molte persone utilizzerebbero un MUA dedicato su tale dispositivo - quindi il rischio di un'impronta digitale si verifica solo se un client di posta elettronica basato sul Web utilizza pesantemente il caching del contenuto (erk! ) o il sistema di autenticazione non sta usando TLS (erk!) o (e questo potenzialmente si applica a dispositivi non pubblici) il terminale è compromesso. Nella maggior parte dei casi, mi aspetto che, avendo acceduto al messaggio contenente il token, l'utente lo approvi e, con la vecchia password incorporata in quel token, cessi di essere riutilizzabile. È corretto incorporare la password salata e hash nel token usando hash e sali opportunamente forti, ma mi dà una sensazione di disagio. Pensavamo che 3DES e MD5 fossero sicuri. Ma ci sono alternative all'invio della password con hash per impedire i replay. I dati rappresentano solo lo stato del record dell'account in un momento specifico. Potresti usare un numero di versione o una data. Ma ciò significa scrivere dati serveride.

    
risposta data 06.01.2017 - 22:03
fonte
1

Opzione 1. Questa è davvero la strada da percorrere e una pratica ben nota. Sicuramente vuoi un nonce a tempo limitato. Leggi anche qui: link

    
risposta data 06.01.2017 - 21:41
fonte
0

Un difetto con il secondo approccio (valore firmato / HMACed) è che crea un singolo punto di errore nel tuo sistema di autenticazione: se un utente malintenzionato riesce a rubare quella chiave di firma / HMAC, sei fregato. L'utente malintenzionato può quindi generare token di ripristino password validi per account arbitrari.

Di solito è più semplice leggere i dati da un server (i file arbitrari includono bug, come i vulns di entità esterne XML, sono piuttosto comuni) o il sistema di compilazione (se il codice sorgente non è abbastanza sicuro, o qualcuno mette gli artefatti di costruzione su un FTP pubblicamente leggibile, o qualcuno compromette i tuoi backup, o qualcosa del genere) piuttosto che scrivere in un database (e se l'hacker può scrivere il tuo database, sei già tostato, possono semplicemente reimpostare le password direttamente). Questo fa parte del motivo per cui la rotazione delle chiavi è una buona idea, ma se qualcuno ruba la tua chiave prima che venga ruotata fuori potrebbe fare un sacco di danno con essa, velocemente.

    
risposta data 11.01.2017 - 10:44
fonte
0

Generating a signed token. From the username or id and a timestamp a signed token is generated with a secret key. This is the link sent to the user. When the user submits the token is decrypted back and the user and timestamp retrieved and validated.

Stai parlando di chiavi segrete, token "firmati" e "decifrazione" (e più tardi, "salt") in un modo molto sciolto che suggerisce che probabilmente stai implementando questo errore. Quello che vorresti usare in questo caso è un codice di autenticazione dei messaggi , ad esempio HMAC-SHA256 , che le tue librerie crittografiche quasi certamente supportano già.

Sei molto saggio essere alla ricerca di attacchi di replay. La tua idea di inviare l'hash salato della password corrente come contesto, mentre non è buona se presa alla lettera, è sulla strada giusta. Quello che ti manca è che non hai bisogno di inserire l'hash nell'URL perché lo stai già archiviando ; tutto ciò che serve per inserire l'URL è l'informazione che consente al server di recuperare l'hash della password salata quando viene fatto clic sull'URL di ripristino. Il nome utente che stai reimpostando la password presumibilmente farebbe il trucco.

Ecco uno schizzo di una possibile soluzione. Innanzitutto, hai bisogno di un% sicuro disecret_key. Un modo per farlo, che può farti risparmiare un sacco di mal di testa, è usare le chiavi effimero - invece di avere una chiave a lungo termine usata per molto tempo e che un attaccante può ancora, cosa fai è invece quando viene avviato il servizio di reimpostazione della password:

  1. Seleziona unsecret_key di 128 bit a caso. Questo verrà sempre mantenuto in memoria, mai scritto su disco o in rete.
  2. Seleziona un startup_uuid unico. Userei un numero casuale o UUID.

Ciò significa che secret_key è valido solo per la durata di un processo di ripristino chiavi: ogni volta che lo riavvii, la chiave viene scartata e ne viene generata una nuova. L'aspetto positivo è che il tuo servizio è molto più resistente alle chiavi rubate. Lo svantaggio è che i link di ripristino generati prima di un riavvio non vengono convalidati: lo scopo di startup_uuid è rilevare tale caso e gestirlo in modo amichevole.

Quando viene richiesto un URL di reimpostazione della password per username , il servizio di reimpostazione password esegue questa operazione:

  1. Scegli un timestamp di scadenza per il link di ripristino, ad esempio 15 minuti dopo l'ora corrente.
  2. Cerca la voce della password username della richiesta e recupera l'hash della password salata corrente.
  3. Costruisci un messaggio delimitato con% delimitato reset_data con i seguenti campi in ordine fisso:
    • Il server elabora ' startup_uuid ;
    • Il nome utente della richiesta;
    • Il timestamp di scadenza selezionato;
    • L'hash della password corrente dell'utente
  4. Calcola reset_token = HMAC-SHA256(secret_key, reset_data)
  5. Costruisci un URL di ripristino con questi valori come parametri. ( NOTA: l'hash della password è non un parametro nell'URL di ripristino!)
    • Il nome utente;
    • Il timestamp di avvio del server;
    • Il timestamp di scadenza;
    • Il reset_token .
  6. Restituisce l'URL costruito.

Quando si riceve una richiesta dall'URL dell'URL di reimpostazione della password:

  1. Se startup_uuid della richiesta non è uguale a quella del server, il servizio è stato riavviato da quando è stato generato il collegamento. Non abbiamo più il vecchio secret_key e quindi non possiamo verificare quella richiesta. L'utente dovrà ripetere la procedura di reimpostazione della password.
  2. Se l'ora corrente è successiva al valore di data e ora di scadenza dell'URL, il link è scaduto, quindi non accettarlo.
  3. Cerca l'hash della password salata per il nome utente della richiesta.
  4. Costruisci un messaggio delimitato non modificato reset_data come sopra.
  5. Verifica che questo messaggio reset-data corrisponda al reset_token incluso nell'URL. Assicurati di farlo in sicurezza con un confronto di parità costante-time.
  6. Se la verifica ha esito positivo, procedi e ripristina la password dell'utente.

Questo protocollo ha queste virtù:

  • Le chiavi segrete sono effimere e vengono sempre conservate nella memoria, quindi anche se qualcuno ruba in qualche modo una chiave è valida solo fino al prossimo riavvio.
  • L'hash della password da ripristinare viene utilizzato come input per HMAC. Se un utente tenta di reimpostare una password che è già stata reimpostata o modificata in altro modo, la verifica del token di reimpostazione non avrà esito positivo.
  • A differenza della tua proposta, la password con hash non viene mai divulgata.
risposta data 11.01.2017 - 03:42
fonte
0

Vorrei puntare all'opzione n. 1 per i seguenti motivi:

  • È compatibile con altre funzionalità di sicurezza. Ad esempio, il codice di reset potrebbe essere consegnato fuori banda (ad esempio SMS). Il codice di ripristino potrebbe essere contrassegnato con l'indirizzo IP o le informazioni di geolocalizzazione nel database e limitare le richieste di ripristino alla stessa posizione. È possibile contare i tentativi di ripristino e valutarli quando si eseguono transazioni ad alto rischio. Ecc.
  • È più facile da implementare. Se si desidera passare un token anziché un codice, il token non solo deve essere firmato ma anche codificato in modo che passi correttamente attraverso firewall e-mail, sistemi DLP, proxy, ecc. Una sequenza di caratteri errata e il token potrebbe essere bloccato o alterato da altre funzionalità di sicurezza. Per tutto il tempo, lavorare su questi argomenti potrebbe essere indirizzato invece a concentrarsi su ulteriori miglioramenti della sicurezza.

Se sei preoccupato per troppi inserimenti di database, limita un utente a una manciata di codici su base FIFO. Ad esempio, GMAIL ti limita a 10 codici di backup.

    
risposta data 24.02.2017 - 22:00
fonte

Leggi altre domande sui tag