Creazione di un'API per applicazioni mobili - Autenticazione e autorizzazione


189

Panoramica

Sto cercando di creare un'API (REST) ​​per la mia applicazione. Lo scopo iniziale / primario sarà per il consumo da app mobili (iPhone, Android, Symbian, ecc.). Ho esaminato diversi meccanismi di autenticazione e autorizzazione per le API basate sul web (studiando altre implementazioni). Ho la testa avvolta attorno alla maggior parte dei concetti fondamentali, ma sto ancora cercando una guida in alcune aree. L'ultima cosa che voglio fare è reinventare la ruota, ma non trovo soluzioni standard che soddisfino i miei criteri (tuttavia i miei criteri sono sbagliati, quindi sentiti libero di criticare anche quello). Inoltre, voglio che l'API sia la stessa per tutte le piattaforme / applicazioni che la utilizzano.

oAuth

Vado avanti e lancio la mia obiezione a oAuth poiché so che probabilmente sarà la prima soluzione offerta. Per le applicazioni mobili (o più specificamente le applicazioni non web), sembra sbagliato lasciare l'applicazione (per accedere a un browser Web) per l'autenticazione. Inoltre, non è possibile (sono a conoscenza) che il browser restituisca il callback all'applicazione (in particolare multipiattaforma). Conosco un paio di app che lo fanno, ma mi sento male e fa una pausa nell'UX dell'applicazione.

Requisiti

  1. L'utente inserisce nome utente / password nell'applicazione.
  2. Ogni chiamata API viene identificata dall'applicazione chiamante.
  3. Il sovraccarico è ridotto al minimo e l'aspetto degli autori è intuitivo per gli sviluppatori.
  4. Il meccanismo è sicuro sia per l'utente finale (le sue credenziali di accesso non sono esposte) sia per lo sviluppatore (le loro credenziali dell'applicazione non sono esposte).
  5. Se possibile, non richiedere https (non è affatto un requisito difficile).

I miei pensieri attuali sull'implementazione

Uno sviluppatore esterno richiederà un account API. Riceveranno un apikey e un apisecret. Ogni richiesta richiederà almeno tre parametri.

  • apikey: dato allo sviluppatore alla registrazione
  • timestamp - funge anche da identificatore univoco per ciascun messaggio per un dato apikey
  • hash: un hash del timestamp + l'apisecret

L'apikey è necessario per identificare l'applicazione che ha emesso la richiesta. Il timestamp agisce in modo simile a oauth_nonce ed evita / mitiga gli attacchi di riproduzione. L'hash assicura che la richiesta sia stata effettivamente emessa dal proprietario dell'apikey specificato.

Per le richieste autenticate (quelle fatte per conto di un utente), sono ancora indeciso tra una route access_token o una combinazione di hash nome utente e password. Ad ogni modo, ad un certo punto sarà richiesta una combinazione nome utente / password. Quindi, quando lo fa, verrebbe utilizzato un hash di più informazioni (apikey, apisecret, timestamp) + la password. Mi piacerebbe un feedback su questo aspetto. Cordiali saluti, dovrebbero prima hash la password, dal momento che non memorizzo le password nel mio sistema senza hash.

Conclusione

Cordiali saluti, questa non è una richiesta per come costruire / strutturare l'API in generale solo come gestire l'autenticazione e l'autorizzazione esclusivamente all'interno di un'applicazione.

Pensieri casuali / domande bonus

Per le API che richiedono solo un'apikey come parte della richiesta, come evitare che qualcuno diverso dal proprietario dell'apikey sia in grado di vedere l'apikey (dal momento che è stato inviato in chiaro) e fare richieste eccessive per superare i limiti di utilizzo? Forse sto solo pensando a questo, ma non dovrebbe esserci qualcosa per autenticare che una richiesta è stata verificata per il proprietario di Apikey? Nel mio caso, quello era lo scopo dell'apisecret, che non è mai mostrato / trasmesso senza essere sottoposto a hash.

A proposito di hash, che dire di md5 vs hmac-sha1? Importa davvero quando tutti i valori sono sottoposti a hash con dati sufficientemente lunghi (es. Apisecret)?

In precedenza avevo considerato l'aggiunta di un salt per utente / riga all'hash della password dei miei utenti. Se dovessi farlo, come potrebbe l'applicazione essere in grado di creare un hash corrispondente senza conoscere il sale utilizzato?


1
Speravo di ottenere qualche altro commento / suggerimento. La domanda è troppo vaga / ambigua?
jsuggs,

6
la domanda è perfetta ma, anche quasi 2 anni dopo, le implementazioni oauth sembrano essere arcane ... sto avendo il tempo più difficile per raggiungere esattamente ciò di cui hai discusso sopra. ho una dimensione aggiuntiva: non voglio usare una coppia loginName / password - voglio usare la verifica dell'identità di google su Android / iOS (Symbian è stata dichiarata dal WWF "specie quasi estinta") e mi rifiuto di sviluppare per Windows Mobile (come lo chiamano in questi giorni).
tony gil,

8
è ridicolo che, come tutti suggeriscono oauth 2.0, di trovare ancora un tutorial o un esempio chiaro e semplice che usi l'inglese comune per spiegare i passaggi, i requisiti, le cose da fare e quelle da fare ...
ChuckKelly,

2
Leggere in questo flusso specifico di OAuth2.0 (Il flusso di password del proprietario della risorsa). Nessun reindirizzamento al sito Web. techblog.hybris.com/2012/06/11/…
Franklin,

1
Sto anche cercando la stessa risposta. Ho trovato un buon articolo che è stato scritto di recente. Spero che aiuti. stormpath.com/blog/the-ultimate-guide-to-mobile-api-security
New to Rails

Risposte:


44

Il modo in cui sto pensando di fare la parte di login di questo nei miei progetti è:

  1. prima dell'accesso l'utente richiede a login_tokendal server. Questi vengono generati e memorizzati sul server su richiesta e probabilmente hanno una durata limitata.

  2. per accedere l'applicazione calcola l'hash della password dell'utente, quindi esegue l'hashing della password login_tokenper ottenere un valore, quindi restituiscono sia l' login_tokenhash combinato che quello combinato.

  3. Il server controlla login_tokenquello che ha generato, rimuovendolo dal suo elenco di messaggi validi login_token. Il server quindi combina l'hash memorizzato della password dell'utente con il login_tokene garantisce che corrisponda al token combinato inviato. Se corrisponde, hai autenticato il tuo utente.

I vantaggi di questo sono che non memorizzi mai la password dell'utente sul server, la password non viene mai passata in chiaro, l'hash della password viene passato solo in chiaro alla creazione dell'account (anche se potrebbero esserci modi per aggirare questo), e dovrebbe essere al sicuro dagli attacchi di replay in quanto login_tokenviene rimosso dal DB in uso.


Grazie, ho dimenticato di aggiungere la parte relativa all'hash della password sul lato dell'applicazione. Non memorizzo le password dei miei utenti in chiaro (ho l'hash prima della memorizzazione).
jsuggs,

2
Vedo un aspetto negativo di questo metodo: non è possibile memorizzare password salate nel database. Se gli aggressori pongono le mani sul tuo DB non dovranno effettuare alcuna decodifica. Poiché l'hash della password è la vera password in questo schema.
sigod,

2
@sigod Hai ragione. Anche se penso che ci sia una dicotomia fondamentale lì - o devi fidarti del tuo trasporto o devi fidarti del tuo deposito. I sistemi di accesso che utilizzano password salate si affidano al livello di trasporto e quindi trasmettono la password dall'utente al sistema di autenticazione in chiaro. Questo caso non si fida del livello di trasporto (penso che ciò sia dovuto al fatto che la piattaforma che stavo prendendo di mira aveva un cattivo supporto per SHTTP). Se ti fidi del livello di trasporto, potresti essere in grado di effettuare altri compromessi.
Michael Anderson,

Ho 3 problemi: 1) come viene mai memorizzata la password dell'utente sul server? nel passaggio 2 hai menzionato che memorizza la password dell'utente con hash. 2) La password dell'utente non viene mai passata in chiaro. Ma in realtà è hash sul client e quindi confrontato con la password con hash sul server, che è quasi la stessa cosa del passaggio e della sua memorizzazione in chiaro, che senso ha farlo? 3) Questo metodo presuppone che l'attaccante non sappia come hash di login_token + password, il che viola il principio di Kerckhoff e lo rende davvero insicuro.
Tamer Shlash,

14

Sono un sacco di domande in una, immagino che molte persone non sono riuscite a leggere fino alla fine :)

La mia esperienza di autenticazione del servizio Web è che le persone di solito la progettano in modo eccessivo e i problemi sono solo gli stessi che si incontrerebbero in una pagina Web. Le possibili opzioni molto semplici includono https per il passaggio di accesso, restituzione di un token, che richiede di essere incluso in richieste future. È inoltre possibile utilizzare l'autenticazione di base http e semplicemente passare elementi nell'intestazione. Per maggiore sicurezza, ruotare / scadere frequentemente i token, verificare che le richieste provengano dallo stesso blocco IP (ciò potrebbe diventare confuso anche se gli utenti mobili si spostano tra le celle), combinare con chiave API o simili. In alternativa, esegui il passaggio "richiesta chiave" di oauth (qualcuno l'ha già suggerito in una risposta precedente ed è una buona idea) prima di autenticare l'utente e utilizzalo come chiave richiesta per generare il token di accesso.

Un'alternativa che non ho ancora usato ma di cui ho sentito parlare come alternativa al dispositivo oAuth è xAuth . Dai un'occhiata e se lo usi, sarei davvero interessato a sapere quali sono le tue impressioni.

Per quanto riguarda l'hashing, sha1 è un po 'meglio, ma non preoccuparti: qualunque cosa i dispositivi possano facilmente (e rapidamente in termini di prestazioni) implementare probabilmente va bene.

Spero che ti aiuti, buona fortuna :)


Grazie per la risposta. Ho esaminato xAuth e quella potrebbe essere la strada che percorro in modo da poter finire con un'installazione oAuth, che rende un processo più standardizzato per interagire con l'API.
jsuggs,

9

Quindi, quello che stai cercando è una sorta di meccanismo di autenticazione lato server che gestirà gli aspetti di autenticazione e autorizzazione di un'applicazione mobile?

Supponendo che questo sia il caso, allora lo approccerei come segue (ma solo perché sono uno sviluppatore Java quindi un ragazzo C # lo farebbe diversamente):

Il servizio di autenticazione e autorizzazione RESTful

  1. Questo funzionerà solo su HTTPS per evitare intercettazioni.
  2. Si baserà su una combinazione di RESTEasy , Spring Security e CAS (per l'accesso singolo su più applicazioni).
  3. Funzionerà con entrambi i browser e le applicazioni client abilitate al web
  4. Ci sarà un'interfaccia di gestione dell'account basata sul web per consentire agli utenti di modificare i propri dettagli e gli amministratori (per applicazioni particolari) per modificare i livelli di autorizzazione

La libreria / applicazione di sicurezza lato client

  1. Per ciascuna piattaforma supportata (ad es. Symbian, Android, iOS ecc.) Creare un'implementazione adeguata della libreria di sicurezza nella lingua nativa della piattaforma (ad es. Java, ObjectiveC, C ecc.)
  2. La libreria dovrebbe gestire la formazione delle richieste HTTPS utilizzando le API disponibili per la piattaforma specificata (ad es. Java utilizza URLConnection ecc.)
  3. I consumatori della libreria generale di autenticazione e autorizzazione (perché è tutto ciò che è) codificheranno su un'interfaccia specifica e non saranno felici se cambieranno, quindi assicurati che sia molto flessibile. Segui le scelte di progettazione esistenti come Spring Security.

Quindi, ora che la vista da 30.000 piedi è completa, come procedi? Bene, non è così difficile creare un sistema di autenticazione e autorizzazione basato sulle tecnologie elencate sul lato server con un client browser. In combinazione con HTTPS, i framework forniranno un processo sicuro basato su un token condiviso (generalmente presentato come cookie) generato dal processo di autenticazione e utilizzato ogni volta che l'utente desidera fare qualcosa. Questo token viene presentato dal client al server ogni volta che si verifica una richiesta.

Nel caso dell'applicazione mobile locale, sembra che tu stia cercando una soluzione che procede come segue:

  1. L'applicazione client ha un Elenco di controllo di accesso (ACL) definito che controlla l'accesso di runtime alle chiamate di metodo. Ad esempio, un determinato utente può leggere una raccolta da un metodo, ma la sua ACL consente l'accesso solo agli oggetti che hanno una Q nel loro nome, quindi alcuni dati nella raccolta vengono estratti silenziosamente dall'intercettore di sicurezza. In Java questo è semplice, basta usare le annotazioni di Spring Security sul codice chiamante e implementare un adeguato processo di risposta ACL. In altre lingue, sei da solo e probabilmente dovrai fornire il codice di sicurezza del bollettino che chiama nella tua libreria di sicurezza. Se il linguaggio supporta AOP (Aspect Oriented Programming), utilizzalo al meglio per questa situazione.
  2. La libreria di sicurezza memorizza nella cache l'elenco completo delle autorizzazioni nella sua memoria privata per l'applicazione corrente in modo che non debba rimanere connessa. A seconda della durata della sessione di accesso, questa potrebbe essere un'operazione una tantum che non viene mai ripetuta.

Qualunque cosa tu faccia, non cercare di inventare il tuo protocollo di sicurezza o utilizzare la sicurezza per oscurità. Non sarai mai in grado di scrivere un algoritmo migliore per questo rispetto a quelli che sono attualmente disponibili e gratuiti. Inoltre, le persone si fidano di algoritmi ben noti. Quindi, se dici che la tua libreria di sicurezza fornisce l'autorizzazione e l'autenticazione per le applicazioni mobili locali utilizzando una combinazione di token crittografati SSL, HTTPS, SpringSecurity e AES, avrai immediatamente credibilità sul mercato.

Spero che questo aiuti, e buona fortuna con la tua impresa. Se desideri maggiori informazioni, fammi sapere - ho scritto alcune applicazioni web basate su Spring Security, ACL e simili.


Grazie, buone informazioni. Un paio di domande. Innanzitutto, se l'intercettazione è accettabile (non sono sicuro che sia / non sia, la mia applicazione in mente non ha alcuna informazione personale / preziosa reale, ma se lo facesse la mia logica cambierebbe) allora l'HTTPS è effettivamente richiesto?
jsuggs,

Se lo desideri, puoi utilizzare l'intero sistema al di fuori di HTTPS. HTTPS serve solo a proteggere le informazioni segrete, quindi suppongo che durante la fase di autenticazione lo faresti tramite HTTPS per fornire una garanzia che il tuo nome utente / password / segreto siano tenuti segreti. Dopo che il token è stato consegnato nella risposta, è possibile inoltrare ulteriori richieste in chiaro se le informazioni contenute nel flusso (che richiedevano l'autenticazione per ottenere) non necessitano di protezione dagli intercettatori.
Gary Rowe,

Inoltre, questa descrizione del protocollo di autenticazione CAS può essere utile: jasig.org/cas/protocol
Gary Rowe,

9

Twitter ha risolto il problema dell'applicazione esterna in oAuth supportando una variante che chiamano xAuth . Sfortunatamente c'è già una pletora di altri schemi con questo nome, quindi può essere confuso risolvere.

Il protocollo è oAuth, tranne per il fatto che salta la fase del token di richiesta e genera immediatamente una coppia di token di accesso alla ricezione di un nome utente e una password. (A partire dal passaggio E qui .) Questa richiesta iniziale e risposta devono essere protette- sta inviando il nome utente e la password in chiaro e sta ricevendo il token di accesso e il token segreto. Dopo aver configurato la coppia di token di accesso, se lo scambio iniziale di token è stato effettuato tramite il modello oAuth o il modello xAuth è irrilevante sia per il client che per il server per il resto della sessione. Questo ha il vantaggio di poter sfruttare l'infrastruttura oAuth esistente e avere quasi la stessa implementazione per le applicazioni mobili / web / desktop. Lo svantaggio principale è che all'applicazione viene concesso l'accesso al nome utente e alla password del client, ma sembra che le tue esigenze impongano questo approccio.

In ogni caso, vorrei essere d'accordo con la tua intuizione e quella di molti altri risponditori qui: non provare a costruire qualcosa di nuovo da zero. I protocolli di sicurezza possono essere facili da avviare ma sono sempre difficili da fare bene, e più sono contorti e meno probabile è che i tuoi sviluppatori di terze parti siano in grado di implementarli. Il tuo ipotetico protocollo è molto simile a o (x) Auth - api_key / api_secret, nonce, sha1 hashing - ma invece di essere in grado di utilizzare una delle tante librerie esistenti, i tuoi sviluppatori dovranno farne le proprie.


2
Devo anche sottolineare che sembra che l'endpoint 'skip request token' sarà in oAuth 2, è elencato nella bozza corrente come tipo di concessione di accesso "password". Vedere la sezione 4.1.2: tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.2
lantius

Come ho detto a Lonra, sto esaminando di più xAuth e in particolare per i motivi che hai citato alla fine ... gli sviluppatori possono "off the shelf" o strumenti / librerie oAuth per interagire con la mia API, che è "una buona cosa" .
jsuggs,

6

Super tardi alla festa, ma volevo aggiungere alcuni punti aggiuntivi da considerare per chiunque fosse interessato a questo problema. Lavoro per un'azienda che sta realizzando soluzioni di sicurezza per API mobili ( approov ), quindi questa intera area è sicuramente rilevante per i miei interessi.

Per cominciare, la cosa più importante da considerare quando si cerca di proteggere un'API mobile è quanto vale per te . La soluzione giusta per una banca è diversa dalla soluzione giusta per qualcuno che fa semplicemente cose per divertimento.

Nella soluzione proposta menzionate che saranno richiesti almeno tre parametri:

  • apikey: assegnato allo sviluppatore al momento della registrazione
  • timestamp - funge anche da identificatore univoco per ciascun messaggio per un dato apikey
  • hash: un hash del timestamp + l'apisecret

Ciò implica che per alcune chiamate API non sono richiesti nome utente / password. Ciò può essere utile per le applicazioni in cui non si desidera forzare un accesso (ad esempio, la navigazione nei negozi online).

Questo è un problema leggermente diverso da quello dell'autenticazione dell'utente ed è più simile all'autenticazione o all'attestazione del software. Non ci sono utenti, ma vuoi comunque assicurarti che non ci siano accessi dannosi alla tua API. Quindi usi il tuo segreto API per firmare il traffico e identificare il codice che accede all'API come autentico. Il potenziale problema con questa soluzione è che devi svelare il segreto all'interno di ogni versione dell'app. Se qualcuno può estrarre il segreto, può usare la tua API, impersonando il tuo software ma facendo quello che vuole.

Per contrastare quella minaccia ci sono un sacco di cose che puoi fare a seconda di quanto siano preziosi i dati. Offuscazione è un modo semplice per rendere più difficile l'estrazione del segreto. Ci sono strumenti che lo faranno per te, più per Android, ma devi ancora avere un codice che generi il tuo hash e un individuo sufficientemente esperto può sempre semplicemente chiamare la funzione che esegue direttamente l'hash.

Un altro modo per attenuare contro l'uso eccessivo di un'API che non richiede un account di accesso è quello di strozzare il traffico e potenzialmente identificare e bloccare gli indirizzi IP sospetti. La quantità di sforzo che vuoi fare dipenderà in gran parte dalla validità dei tuoi dati.

Oltre a ciò puoi facilmente iniziare ad entrare nel dominio del mio lavoro quotidiano. Ad ogni modo, è un altro aspetto della protezione delle API che ritengo importante e che vorrei segnalare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.