Attenua la minaccia di attacco a tempo rispetto alla pagina di recupero password

15

Recentemente abbiamo eseguito una revisione della sicurezza esterna su un sito web pubblico che gestiamo. Hanno notato che nella "pagina di recupero della password" ci sono diversi tempi di risposta quando si forniscono nomi utente esistenti e non esistenti. Affermano che questo potrebbe rendere più facile per un utente malintenzionato verificare i nomi utente esistenti. La modifica suggerita per eliminare questo vettore di attacco è quella di eseguire sempre la stessa logica per ogni tentativo di recupero della password.

Nel nostro caso, la logica di recupero della password consiste (approssimativamente) nei seguenti passaggi:

  1. Carica l'utente dal database.
  2. Invia un'email all'utente con un link per la reimpostazione della password.

Se l'utente esiste, vengono eseguiti entrambi i passaggi. Se l'utente non esiste, viene eseguito solo il passaggio 1.

In termini di ricerche nel database, ecc., questo è facilmente risolvibile. Ma quando si tratta di interagire con sistemi esterni, in questo caso l'invio di una e-mail, è meno banale.

Supponevo che introdurre un ritardo casuale non sarebbe di grande aiuto, poiché probabilmente ci sarebbe ancora una differenza rilevabile nelle distribuzioni dei tempi di risposta.

Un'altra idea è quella di creare un account e-mail da qualche parte e inviare lì un messaggio di posta elettronica per ogni nome utente non esistente.

Quale sarebbe la migliore pratica in questa situazione?

    
posta MEMark 09.10.2015 - 15:55
fonte

7 risposte

7

Ho visto questo fatto in un paio di modi, uno che hai già menzionato usando aggiunte temporali casuali (non ne sono un fan), due rendendo il compito asincrono come ha detto il phyrfox (questo funziona bene se lo si può fare), ma ultimamente three ; avendo una durata minima forzata per la risposta alla pagina. Non sono sicuro di quello che penso di questo metodo vs numero due, ma lo descriverò comunque in ogni caso:

La logica di base nella tua situazione potrebbe essere simile a:

  1. registra la data / ora del sistema
  2. carica utente dal database
  3. Invia un'email all'utente con un link per la reimpostazione della password
  4. controlla la differenza di orario tra ora e il timestamp del passaggio 1. Se la differenza x è inferiore alla durata minima
  5. ritardo del completamento della risposta di x meno il tempo trascorso finora.

Questo ha un paio di buoni punti e un paio di punti negativi ..

buona:

  • Alcuni altri meccanismi di livello inferiore si concentrano sull'ottenere che ogni gradino atomico impieghi lo stesso tempo, nel tuo scenario devi assicurarti che il tempo totale di tutti i passaggi sia lo stesso, questo è un modo per farlo .
  • è un'implementazione rapida e facile del codice.

cattivo:

  • se qualcuno può causare un ritardo in un componente, può estendere il tempo impiegato oltre un minium con hard codifica. Ad esempio, se in media il viaggio di andata e ritorno impiega 1 secondo, è possibile applicare una durata minima di 1,5 secondi. Se il tempo di risposta del server del database viene aumentato a causa di attività dannose o dannose, è possibile che il tempo di risposta medio venga spinto fino a 2 secondi, oltre la durata minima. Puoi provare ad aggirare questo problema utilizzando una durata minima dinamica, in base alla durata media delle richieste recenti, ad esempio (ma con un valore minimo impostato).
  • stai rendendo più facile il tuo sistema soffrire un DOS con più richieste di pagine con questo tipo di meccanismo. Il luogo che ho visto usando questo trucco ha recentemente considerato questo rischio come il minore di due mali.

Modifica

Dato che non posso commentare altre risposte, volevo solo sottolineare che su sistemi che non hanno registrazioni aperte, vuoi provare a mantenere il segreto del nome utente, e indipendentemente dal fatto che i tuoi nomi utente siano esposti in base alla progettazione durante il normale uso del tuo sistema - difesa in profondità! Perché renderlo più semplice di quanto dovrebbe essere?

Appena in cima alla mia testa: se riesci a numerare rapidamente migliaia di utenti, aumenta il numero di account che potrebbero avere password semplici per la forza bruta, o forse potresti esporre i tuoi utenti ad altri vettori di attacco come attacchi di spear phishing o social engineering. Meno informazioni hanno i cattivi sui tuoi utenti, meglio è.

    
risposta data 09.10.2015 - 16:52
fonte
11

Facciamo la vera domanda qui:

L'elenco dei nomi utente associati alla tua domanda è segreto?

Genere di ma principalmente NO . Di solito, ogni nome utente è unico in un'applicazione, quindi è molto difficile se non impossibile tenerlo segreto. Ad esempio, un modo che molto spesso funziona (se non sempre) per trovare il nome utente associato alla tua applicazione è semplicemente creare un nuovo account. Quando inserisci un nome utente, il processo di creazione ti dirà se è già stato preso o meno. Quindi, puoi creare lentamente un elenco di nome utente valido.

In generale, non ha molto senso cercare di mantenere il nome utente segreto ed è probabilmente impossibile, quindi rinunciare a quella parte.

È interessante leggere come Il tuo nome utente non è un segreto .

Che cosa dovrebbe provare a proteggere?

Devi proteggere i segreti associati al nome utente; password e qualsiasi altra forma di autenticazione. È qui che ha senso preoccuparsi dell'attacco temporale. Ad esempio, il codice di verifica della password deve richiedere lo stesso tempo se i primi 2 caratteri corrispondono a se nessun carattere corrisponde affatto.

Nota aggiuntiva

Proteggere l'autenticazione a più fattori è un altro argomento interessante. Non è direttamente un attacco a tempo, ma è lo stesso principio. Ad esempio, se hai una password e un codice telefonico necessari per accedere a un'app. Se l'applicazione ti chiede solo il codice del telefono quando la password è corretta, rende molto più facile per l'utente malintenzionato trovare la password che se l'applicazione richiedesse la password E il codice telefonico ogni volta. Ma c'è qualche problema sulla privacy del numero di telefono se lo chiedi ogni volta ...

    
risposta data 09.10.2015 - 16:34
fonte
10

Potresti scegliere di eseguire le azioni in modo asincrono, dando l'impressione di avere un tempo lineare. In termini di pseudo-codice, puoi sempre fare qualcosa del genere:

Sleep 1000 ; Sleep for a second
Output template ; Show a confirmation page
Close Socket ; Make the browser/client believe we're done
Lookup User From Database ; Try to load the user
If User Found
    Send Email ; Send an Email
End If

Conosco almeno un servizio che fa questo; l'utente vedrà sempre un messaggio di conferma ("Ottimo, ora controlla la tua email") senza confermare effettivamente se l'utente esiste e / o è stata inviata un'email. Ciò elimina tutti i tempi delle variabili sotto il tuo controllo, inclusi i tempi di ricerca del database e il tempo necessario per l'invio dell'e-mail.

Non tutte le lingue supportano direttamente questo tipo di modello, ma potresti essere in grado di usare fork () per generare un processo (o qualsiasi altro metodo fornito dal tuo linguaggio) per eseguire il codice in modo asincrono.

Ciò lascia problemi di temporizzazione solo all'utilità di pianificazione del sistema operativo e non in base alla logica effettiva eseguita. L'introduzione di un ritardo artificiale attenuerà anche alcuni tipi di programmi che non sono multithreaded, poiché dovranno aspettare un secondo per ogni tentativo (non una buona difesa, ma molti strumenti di "hacking" non sono comunque comunque multithreaded).

Anche senza il ritardo, tuttavia, non sarebbero ancora in grado di confermare se l'account utente fosse effettivamente valido o meno, quindi l'attacco sarebbe mitigato. L'unica cosa che devi fare è stabilizzare la quantità di tempo necessaria per ricevere una risposta; una ricerca andata a buon fine e una ricerca fallita dovrebbero richiedere esattamente lo stesso tempo.

    
risposta data 09.10.2015 - 16:24
fonte
4

La randomizzazione di qualsiasi tipo attenuerà solo l'attacco, richiedendo più statistiche prima che si possa osservare una differenza temporale. Questa non è una buona soluzione, a meno che non sia la migliore che si possa fare.

Il mio suggerimento, invece, è di avere un processo in background che mandi email. Il processo di recupero effettivo non controllerebbe nemmeno se il nome utente è valido, invierà solo un messaggio al processo in background (con qualsiasi metodo IPC conveniente) dicendo di inviare l'e-mail per nome utente così-e-così e restituire immediatamente il messaggio " fatto "pagina.

Il processo in background gestirà effettivamente se il nome utente è valido e invierà l'e-mail in tal caso, ma i suoi risultati e i suoi tempi non dovrebbero essere osservabili da un utente malintenzionato remoto.

    
risposta data 10.10.2015 - 07:56
fonte
0

Per risolvere questo problema, è sufficiente consentire al programma di inviare la pagina di risposta a determinati intervalli di wall-clock. In questo modo, finché il tempo effettivo richiesto per terminare l'elaborazione è più breve dell'intervallo tra un intervallo, risponderà sempre in un modo che è inutile per questo attacco.

Quindi, quando scegli un intervallo, sii generoso.

Ciò che intendo è: La pagina di recupero della password può rispondere solo 4 volte al minuto.

[00:00]

[00:07] L'elaborazione inizia

[00:09] (Elaborazione completata per nome utente non valido)

[00:14] (L'elaborazione è stata completata con nome utente valido)

[00:15] (in attesa ...)

[00:30] (Risposta inviata)

[00:45]

[01:00]

...

Se l'elaborazione termina tra uno qualsiasi di questi intervalli, attende il successivo intervallo per rispondere.

    
risposta data 10.10.2015 - 09:16
fonte
0

Penso che ci sia una soluzione molto semplice a questo problema e sono un po 'sorpreso che non sia stato menzionato. Mettendo da parte tutte le domande su se i nomi utente sono segreti o no, tutto ciò che devi fare è cambiare la logica.

Invece di verificare che l'utente sia valido e quindi di visualizzare il messaggio all'utente, è sufficiente rispondere con una risposta standard per tutti i tentativi di reimpostazione della password e farlo PRIMA di effettuare qualsiasi tentativo di verifica dell'account. Basta inviare una risposta lungo le linee "Se si dispone di un account valido su questo sistema, verrà inviato un link di reimpostazione della password al proprio indirizzo e-mail". Se lo fai prima, otterrai (in modo critico) lo stesso tempo di risposta per le richieste valide e non valide. Dopo aver inviato la risposta, quindi verificare i dati e se sembra legittimo, inviare l'e-mail.

L'unica limitazione sarà che avresti bisogno di impostarlo in modo tale che lo stage che gestisce l'invio del link e-mail dovrà essere fatto in un processo separato in modo che tu possa rispondere e terminare la connessione web iniziale. Questo può essere fatto semplicemente registrando la richiesta in una tabella di database e avendo un altro processo che cerca i nuovi record in questa tabella su una pianificazione regolare e li elabora di conseguenza.

    
risposta data 16.10.2015 - 00:40
fonte
-1

Aggiungi una quantità casuale di tempo di sonno che si sovrappone alla differenza di tempo tra nomi utente esistenti / non esistenti.

vale a dire. se lo scenario attuale è,

A) Tempo di risposta del nome utente esistente = 50 ms

B) Tempo di risposta del nome utente non esistente = 120 ms

Aggiungi 70-100 ms di tempo di sonno casuale a A (120-150 ms)

Aggiungi 0-30 ms di tempo di sonno casuale a B (120-150 ms).

    
risposta data 09.10.2015 - 21:13
fonte

Leggi altre domande sui tag