Come testare efficacemente il rischio di enumerazione del nome utente?

2

Sono responsabile di alcune applicazioni Web pubbliche e voglio testarle per il rischio di enumerazione del nome utente come spiegato in Test per l'enumerazione utente e l'account utente prescelto (OWASP-AT-002) dal progetto OWASP.

Queste applicazioni sono siti Web basati su .NET, con un accesso standard costituito da nome utente / password e in genere una funzionalità di reimpostazione della password.

Potrei farlo a mano, naturalmente, (almeno per le differenze visive) ma preferirei usare un metodo automatico.

Il test dovrebbe includere:

  • (Visual) Differenziazione basata sui contenuti (semplice per un tester umano)
  • Differenziale basato sulla risposta (HTML-Text)
  • Differenziazione basata sul tempo (Risposta più veloce / più lenta alla corrispondenza)
  • altri che ho dimenticato?

Il test non dovrebbe includere la supposizione della password (reale), solo l'enumerazione del nome utente. Ho un set di nomi utente noti con cui testare, insieme agli URL della schermata di accesso.

Che cos'è un metodo semplice ed efficace per testare un rischio di enumerazione del nome utente?

    
posta Marcel 19.09.2016 - 16:49
fonte

1 risposta

2
La differenziazione

visiva è una conseguenza della differenziazione HTML. Non può succedere che lo stesso HTML + JS + CSS porti a visualizzazioni diverse (salvo alcune correzioni intenzionali come, non so ... colori di sfondo dipendenti dal tempo o animazioni?).

Quindi puoi inviare un numero sufficiente di query per utenti reali e confrontare le stesse query per gli utenti fasulli; e devi fare lo stesso con tutti gli endpoint non autenticati accessibili.

Questo significa esaminare non solo l'URL di "accesso" ma anche "Ho perso la mia password, come faccio a recuperarla?".

Per ciascuno di questi endpoint, oltre alle differenze nelle uscite, calcola il tempo medio di risposta e la sua varianza (una varianza abbastanza alta negherà qualsiasi ragionevole attacco di temporizzazione).

Potresti volerlo fare due volte, cioè controllare l'utente "marcel" una volta e poi di nuovo. La serie dei "primi" che chiamiamo la serie non imitata , la serie dei "secondi" è la serie innescata .

Elimina i contenuti ricevuti di qualsiasi timestamp, ID univoco o informazioni relative all'utente (es. "Mi dispiace, la password per l'utente marcel è errata" dovrebbe diventare "Spiacente, la password per l'utente USERNAME non è corretta" - è semplice regex qui. l'utente è chiamato table, html, o body, dato che ciò dovrebbe distorcere i risultati).

Quindi il risultato desiderato è quello, per tutti endpoint (1),

  1. tutte le risposte per utenti reali e utenti falsi sono identiche.
  2. le parti rimosse ("marcel", "admin", "20160920173511.128", ecc.) sono tutte identiche o tutte diverse . Ad esempio, non è possibile che gli utenti reali ottengano un timestamp reale e che gli utenti falsi non ottengano il timestamp o un timestamp formattato in modo diverso, ad esempio.
  3. il tempo di risposta per ogni utente falso dovrebbe essere molto vicino al tempo di risposta per un utente reale. Idealmente vuoi la stessa media e varianza.
  4. la distribuzione dei tempi per le serie di utenti reali innescate e non sviluppate potrebbe essere diversa (in genere, i tempi di innesco sono più brevi). Se lo sono, quindi lo stesso rapporto deve essere mantenuto tra le serie innescate e non limitate per gli utenti fasulli.

Il punto 3 indica che la ricerca di un utente che non è nel database deve richiedere lo stesso tempo di un utente che è nel database e che ha i dati da caricare e analizzare. Raggiungerlo non è banale. Ho visto ritardi casuali aggiunti al processo, ma devono essere basati sul nome utente (stesso nome utente = sempre stesso ritardo) (2).

Il punto 4 potrebbe portare ad una svolta negli attacchi temporali, che consente di distinguere tra utenti reali e falsi anche se per un singolo tentativo i tempi di reazione sono gli stessi.

(1) Ho visto diversi sistemi che chiederanno il tuo nome utente per aiutarti a recuperare la password, e allegramente dire "Mi dispiace, quel nome utente non è noto!". Un messaggio più adatto potrebbe essere: "Molto bene, lserni (se questo è veramente il tuo account), se sei nel nostro database, dovresti ricevere una email a breve."

(2) Quando arriva un nome utente, voglio aggiungere un ritardo casuale che impedirà a la maggior parte di tentare di sincronizzare il processo di autenticazione. marcel è risolto in 85 ms e ginepro in 62 ms. È perché esiste il marcel e il ginepro no, o perché i loro ritardi erano diversi? Non devi saperlo. Ma cosa succede se il ritardo per l'utente juniper è casuale ogni volta ? Succede che posso calcolare la media del tempo di risoluzione, e la casualità lentamente (a seconda della sua varianza) si cancellerà. Quindi aggiungo al ginepro dell'utente un ritardo assegnato casualmente al ginepro, ma è sempre lo stesso ogni volta che il ginepro tenta di autenticarsi. Per evitare di salvare le cose in un database huuuuuuge, ciò che I realmente fa è calcolare un CRC a 32 bit dal nome, XOR con un salt segreto, usare il risultato per seminare un PRNG ed estrarre un numero casuale. A quel punto anche se l'utente malintenzionato sa che i nomi utente esistenti ottengono un ritardo di 50 ms mentre i nomi utente sconosciuti ottengono 30, non può sapere se i 62ms di Juniper sono stati dati da 50 più un 12 casuale (esiste il ginepro) o 30 più 32 (nessun ginepro). E il 12 (o 32) non sarà lo stesso per un utente diverso che avrà un CRC32 diverso. Quindi utilizzare lo stesso nome utente non aiuterà, ma l'utilizzo di un nome utente diverso non sarà di aiuto. Certo, ho bisogno di un intervallo casuale abbastanza grande da "sopraffare" la differenza di tempo conosciuta / sconosciuta.

    
risposta data 21.09.2016 - 19:33
fonte

Leggi altre domande sui tag