È sicuro esporre gli hash delle password di bcrypt?

12

Sto costruendo un'app Web che deve supportare il passaggio da utente a offline e mi chiedo se è sicuro esporre gli hash di bcrypt per autenticare gli utenti.

Il flusso di base:

  1. Gli utenti primari eseguono l'accesso mentre l'app Web è online, colpendo il server
  2. Server restituisce un elenco di altri utenti all'interno della stessa azienda, inclusi i loro hash bcrypt (costo hash di 10)
  3. L'altro utente può creare un record mentre l'app Web è offline inserendo la propria password, confrontata con quella restituita in precedenza utilizzando una libreria JS bcrypt

L'applicazione stessa è piuttosto a basso rischio e non ci sono molti scenari in cui un utente sarebbe incentivato a impersonare un collega, ma mi piacerebbe farlo bene.

Grazie in anticipo per qualsiasi approfondimento.

(Una domanda di follow-up è: durante la sincronizzazione con il server, come dimostrare al server che l'altro utente ha effettivamente effettuato l'autenticazione offline prima di creare il loro record, ma che potrebbe essere migliore del suo stesso post.)

    
posta Alex Dunae 25.11.2016 - 21:41
fonte

2 risposte

32

No, non va bene, ma non è una questione di hash bcrypt, ma perché hai spostato l'autenticazione dal server di cui ti fidi (perché è il tuo server) al dispositivo dell'utente (di cui non puoi fidarti). Ora è necessario un semplice debugger per modificare il risultato di "questa password è valida?" controlla da "no" a "sì".

Inoltre, fornisce a un utente malintenzionato un accesso permanente a un elenco di hash. Pertanto, l'autore dell'attacco può forzare tale elenco per tutto il tempo che desidera su qualsiasi computer che desidera utilizzare.

In poche parole, è una pessima idea.

La cosa giusta da fare sarebbe quella di memorizzare nella cache le azioni dell'utente che afferma di essere un collaboratore del tuo utente autenticato e lasciare che quel collega si autentichi correttamente con il tuo server non appena sono tornati online per commettere effettivamente qualsiasi cosa abbiano fatto al server. Un modo per farlo è semplicemente quello di memorizzare la password inserita dall'utente e quindi inviarla al server, in qualsiasi forma si usi durante un login "normale". Se funziona, va bene, l'utente si è autenticato e lo ha memorizzato le azioni possono essere eseguite. In caso contrario, dire all'utente che ha inserito una password errata e che le sue azioni non possono essere eseguite a meno che non entri nella giusta.

    
risposta data 25.11.2016 - 21:45
fonte
3

Spingendo gli hash delle password sul client, li esporresti agli attacchi brute force offline. Questo può essere del tutto accettabile se le password sono sufficientemente forti. Ma questa è un'assunzione pericolosa da fare.

Potresti chiedere ad ogni utente di confermare che vuole che il proprio hash sia pubblicato (dopo aver spiegato il rischio per loro). Ma ci sono molti utenti che sarebbero felici di dire che capiscono il rischio e hanno scelto una password sufficientemente solida anche se ciò che effettivamente scelgono era password12345!!!

A questo punto dovrai valutare l'importanza di questa funzionalità rispetto al rischio di consentire agli utenti di spararsi ai piedi.

C'è tuttavia un altro svantaggio nella progettazione che è quello di autenticare gli aggiornamenti resi offline. Affidarsi al client per convalidare l'utente non è abbastanza buono.

Memorizzando la password dell'utente insieme all'aggiornamento e inviandoli entrambi al server una volta online si risolverebbe il problema di eseguire solo la validazione lato client. Ma introdurrai tre nuovi problemi:

  1. Non acquisisce credenziali digitate erroneamente quando si inseriscono gli aggiornamenti. E in seguito quando tali credenziali vengono verificate dal server, l'utente che le ha digitate in primo luogo potrebbe non essere in giro per risolvere il problema.
  2. L'aggiornamento sarebbe malleabile. Sarebbe banale modificare l'aggiornamento mentre è memorizzato sul dispositivo client per farlo eseguire un aggiornamento diverso una volta arrivato sul server.
  3. Si memorizzano le password in chiaro sul dispositivo che è un grande no-no securitywise.

Non vedo alcun modo per prevenire la forza bruta offline delle password, pur consentendo la convalida della password nel momento in cui viene inserito un aggiornamento, e tale convalida è necessaria per ragioni di usabilità.

L'approccio che prendo quindi è di creare una coppia di chiavi pubbliche basata sulla password degli utenti e su un valore salt e utilizzare la chiave privata corrispondente per firmare l'aggiornamento. Ciò significa che l'aggiornamento non è più malleabile e che la password non deve essere memorizzata e trasmessa, ma solo archiviare e trasmettere la firma.

Ovviamente il cliente dovrebbe comunque conoscere salt e username per generare una transazione correttamente firmata. E sarebbe necessario conoscere la chiave pubblica o un hash per verificarlo in primo luogo, il che consente attacchi di forza bruta offline.

Puoi troncare il lato client verificato dell'hash su un solo byte, il che rende gli attacchi offline a forza bruta meno fattibili e ha ancora il 99% di possibilità di rilevare password errate sul lato client.

Sul lato server, dovresti ancora verificare la chiave pubblica trasmessa utilizzando un hash salato per assicurarti di ricevere solo transazioni valide.

Ovviamente qualsiasi progetto per l'applicazione che stai progettando lascia molto spazio per errori, quindi avere la progettazione finale e la revisione del codice da parte di più professionisti della sicurezza è una necessità per garantire che il risultato finale sia sicuro.

    
risposta data 26.11.2016 - 19:29
fonte