Come si può progettare l'autenticazione utente dalle applicazioni client?

14

Ho sviluppato un'applicazione che supporterà molti utenti. Il fatto è che non sono in grado di capire come autenticare il client / utente.

Sto costruendo un'app come link dove darò le credenziali ai miei utenti e useranno quelle per creare N applicazioni in cui non possono inserire nome utente e password per l'autenticazione.

Supponiamo che vada come segue. (Proprio come QuickBlox)

1. L'utente crea un account sul mio sito Web.
2. L'utente può creare N chiavi API e secernere credenziali. (Per più app)
3. L'utente utilizzerà queste credenziali nelle proprie applicazioni (Android, iOS, Javascript ecc.) Per parlare con le mie API REST.
(Le API REST hanno accesso in lettura e scrittura.)

La mia preoccupazione?

Gli utenti inseriranno le proprie credenziali (chiave API e chiave secondaria) nelle applicazioni che creano, e se qualcuno ottiene queste chiavi e tenta di imitare l'utente? (Decompilando l'APK o esaminando direttamente il codice JavaScript.

Mi sbaglio da qualche parte?
Sono confuso nel progettare questo meccanismo utente a tre livelli.

    
posta Alok Patel 02.08.2016 - 05:44
fonte

7 risposte

6

Ho progettato le API REST negli ultimi anni. Stai preoccupando troppo. Recentemente un altro utente su questo forum ha posto una domanda, dove era preoccupato per memorizzazione degli endpoint URI nel suo codice lato client JavaScript .

Le stesse regole si applicano a te come si applicano allo sviluppatore JavaScript. Se consenti alle persone esterne di integrare la tua API, la tua API ha la stessa visibilità di un normale sito web e dovresti trattarla allo stesso modo.

Citazione dalla risposta originale:

When you are creating a website and you do not want users to do something, you do not implement that functionality or forbid certain users from using it. With a REST API which should have public endpoints it is pretty much the same, you need to treat it like a public website.

Your REST API should be robust enough not to allow invalid operations, such as access to data from a different user.

Dovresti progettare i token di accesso all'applicazione per consentire solo le operazioni che desideri siano consentite. Potresti avere due tipi di token di accesso:

  • token principale : potrebbe essere utilizzato dal creatore dell'applicazione e fornire più funzionalità dalla tua API,
  • token dell'applicazione : il token che verrebbe effettivamente archiviato all'interno delle applicazioni e avrebbe solo un accesso limitato all'API, solo alle operazioni che non possono danneggiare i tuoi oi dati del programmatore dell'applicazione.

Ma ciò che qualcuno decostruisce il codice sorgente, prende i token dall'applicazione, scopre quali sono gli endpoint pubblici e abusa del tuo servizio web?

A meno che tu non stia gestendo direttamente lo sviluppo delle applicazioni che consumano la tua API, nulla impedisce davvero alle persone di abusare della tua API allo stesso modo direttamente dall'app.

    
risposta data 04.08.2016 - 08:16
fonte
5

Il tuo problema non è tanto tecnico quanto commerciale.

Diciamo che hai la tua API, che vendi ai tuoi clienti (gli sviluppatori di app) per un importo forfettario di £ 100 all'anno, accesso illimitato.

Bene, ovviamente, posso acquistare il tuo servizio a £ 100 e venderlo a 10 persone a $ 50 ciascuno. Non lo vuoi! quindi prova a pensare a una restrizione che ti consenta di vendere la tua API senza che sia aperta all'arbitraggio.

  • Se limiti il numero di app, un cliente può creare una singola app che accetta le connessioni da altre app e le inoltra.

  • Se limiti gli utenti, di nuovo, il cliente può nascondere gli utenti dietro la propria autenticazione e apparire come un singolo utente.

Quello che devi fare è trasferire il costo di ogni chiamata API al tuo cliente. cioè addebito per chiamata API o imposta una quota di chiamate all'anno.

Questo spinge lo stesso problema di arbitraggio sui tuoi clienti. Li costringe a mettere in atto misure per impedire ai loro utenti di rubare le loro chiavi. In questo caso, nascondendo la tua API dietro la propria API autenticata dall'utente.

    
risposta data 04.08.2016 - 10:32
fonte
2

Le altre risposte sembrano suggerire che il problema di archiviare un segreto in un'app sui dispositivi consumer non è risolvibile.

Certo che lo è.

Due principi (i dettagli di implementazione seguiranno):

  1. Gli attuali punti finali dell'autenticazione devono essere anonimi aperti al pubblico.
  2. Il server deve in qualche modo essere coinvolto nell'autenticazione del client e nella fornitura di una chiave API.

Dato che, se il client effettua una richiesta al punto finale di autenticazione con credenziali e il server lo autentica, il server può generare un token temporaneo dinamico (significato temporaneo basato sul tempo). Questo token deve essere ricordato all'interno del client e inviato con richieste successive.

Avrai bisogno di un meccanismo per "aggiornare" periodicamente il token, cioè, prendine uno nuovo. Basta creare un endpoint REST che consenta di generare un nuovo token da uno esistente, per evitare di dover autenticare nuovamente le credenziali.

Se stai cercando di evitare che l'utente finale si autentichi di nuovo, questa autenticazione può essere una configurazione iniziale unica nell'app quando viene installata.

Questa soluzione evita semplicemente la necessità di memorizzare un token statico incorporato nel binario dell'applicazione. Un token viene generato al volo dal server solo in risposta a un'autenticazione corretta. Affinché un utente malintenzionato possa ispezionare la tua applicazione e provare a ottenere l'accesso API non autorizzato, dovrebbe comunque autenticarsi come chiunque altro.

    
risposta data 08.08.2016 - 15:37
fonte
0

Se disponi di chiavi univoche per app, puoi utilizzarle solo durante un'autenticazione iniziale della connessione, avviata dal client, dopodiché devi passare a un token di autenticazione unico in rotazione per app.

Il tuo server cambia (rotola) il token per ogni app del client di volta in volta (periodicamente più / meno un ritardo casuale fuzzy / random, ad esempio). Il token di rotolamento è noto solo tra il server e il client autenticato.

I nuovi token vengono restituiti con il dorso nelle risposte regolari. Ogni volta che la risposta contiene un nuovo token, l'app ricevente deve passare al suo utilizzo nelle richieste successive.

Ogni volta che lo scambio con un client non è sincronizzato (qualche errore di protocollo di qualche tipo) il server richiederà la ri-autenticazione (attraverso una risposta di errore alla richiesta successiva del client, o piggy-backed sulla risposta valida al client richiesta, ad esempio).

L'autenticazione iniziale avviata dai client mentre un token rolling viene utilizzato attivamente dovrebbe essere considerata con sospetto - potrebbe benissimo essere un tentativo di imitazione. Lo consentirei solo se lo scambio diventa inattivo per un intervallo più lungo del previsto, che potrebbe, ad esempio, essere causato da un'interruzione / riavvio del client con una nuova istanza che non ha il token di rotolamento.

Sarebbe anche meglio mantenere il token sul lato client in modo tale che un client riavviato possa continuare da dove è rimasto il suo predecessore, riducendo significativamente l'apertura per l'imitazione.

Tale schema renderebbe la mimizzazione almeno abbastanza difficile - il client imitativo dovrebbe prevedere esattamente la finestra quando il client autorizzato interrompe l'invio di richieste abbastanza a lungo da consentire al server di decidere che è OK accettare una nuova autenticazione client con la chiave prescritta può prendere posto. Tali richieste al di fuori della finestra consentita possono essere utilizzate come rilevamento dei tentativi di imitazione e possibilmente avviare alcune contromisure (lista nera IP, ecc.).

    
risposta data 04.08.2016 - 10:03
fonte
0

Da quello che so, quello che hai menzionato è l'unico modo per farlo. L'applicazione che memorizza la chiave è sicuramente un rischio, ma ci sono vari modi per eluderlo. È sempre possibile utilizzare il keystore per memorizzare la chiave, anziché l'hardcoding, forzando così un accesso una tantum.

Inoltre, dovresti considerare di associare una chiave a un client, quindi, se qualcuno imita, dovresti avere un livello di sicurezza per controllare il client, la chiave e i programmi utente per bloccare immediatamente la richiesta. Avere un caso d'uso per ri-emettere o assicurare che le chiavi non siano state imitate.

    
risposta data 04.08.2016 - 07:55
fonte
0

Se dipendi dall'abilitare token di autorizzazione ai tuoi clienti per inserire le loro app, sarà sempre teoricamente possibile per qualcuno decodificare l'app ed estrarla. Per evitare ciò, è necessario un meccanismo che non richieda un segreto all'interno dell'app client. È difficile. Posso suggerirti alcune opzioni per cui puoi pensare.

Hai un problema una volta che hai fornito le credenziali, non hai il controllo su quanto siano archiviate in modo sicuro. Inoltre, se desideri che l'utente ti invii le credenziali, allora qualcuno può MITM la tua connessione e rubare i token direttamente senza preoccuparsi di decodificare l'app.

Un modo per rendere più difficile l'estrazione del token di autorizzazione è di offuscarlo. Questo solleva la barra, ma non lo rende impossibile, e per farlo dovresti mantenere il controllo del segreto. È possibile implementare una libreria che contiene le informazioni segrete ed è specifica per ciascun cliente. Potresti usare la libreria per comunicare con i tuoi server e potresti non dover nemmeno dire al tuo utente le informazioni segrete, potrebbe semplicemente essere incorporato nella libreria. Questo non risolve il problema di qualcuno che decodifica la tua libreria, ma ti mette in controllo del livello di offuscamento. Uno svantaggio è che una volta che una persona ha violato l'oscuramento nella libreria, può attaccare qualsiasi libreria, a meno che non si scriva un codice che rende ogni libreria significativamente diversa. Questo introduce la sua serie di problemi.

Questo potrebbe allontanarsi leggermente dall'ambito della tua domanda, ma è legato alla sicurezza del tuo token quindi ne parlerò. Per evitare il furto insignificante del token sul filo, probabilmente non si desidera inviare direttamente il token, ma è possibile firmare il traffico utilizzando una funzione HMAC. È possibile verificare la validità del messaggio calcolando l'HMAC del messaggio sul server e confrontandolo con l'HMAC inviato dal client. Dovresti usare il token come chiave per la funzione HMAC in modo che solo chi conosce il token possa firmare il traffico. Questo è meglio per la sicurezza del token perché non lo si invia mai direttamente al server in modo che non possa essere intercettato e rubato direttamente. Per maggiori informazioni su HMACS vedi questa domanda: link

Nessuna soluzione di sicurezza sarà inespugnabile, devi decidere quanto ti costerà implementare rispetto alla probabilità e al costo di essere compromessa.

    
risposta data 04.08.2016 - 16:15
fonte
0

Citando te stesso:

I'm unable to figure out, how to authenticate the client/user ... in which they can't put their username and password to get authenticated.

Ora è un po 'una contraddizione, vero? ;)

Come altri hanno detto, non puoi. Se un'app utilizza una chiave API, è possibile decompilarla come dici per ottenere le chiavi e usarla anche.

Oltre a richiedere un'autenticazione utente corretta aggiuntiva, puoi limitare solo il danno:

  • whitelisting / blacklisting IP
  • strozzamento
  • Rilevamento
  • "attività insolite" e relativa fonte
  • rinnovo della chiave facile
risposta data 08.08.2016 - 14:15
fonte