Creazione di un’API per applicazioni mobili – Autenticazione e authorization

Panoramica

Sto cercando di creare un’API (REST) ​​per la mia applicazione. Lo scopo iniziale / primario sarà il consumo da parte delle app mobili (iPhone, Android, Symbian, ecc.). Ho esaminato diversi meccanismi per l’autenticazione e l’authorization per le API basate sul Web (studiando altre implementazioni). Ho la testa contorta sulla maggior parte dei concetti fondamentali, ma sto ancora cercando indicazioni in alcune aree. L’ultima cosa che voglio fare è reinventare la ruota, ma non sto trovando alcuna soluzione standard che si adatta ai miei criteri (tuttavia i miei criteri sono errati e quindi mi sento libero di criticare anche questo). Inoltre, voglio che l’API sia la stessa per tutte le piattaforms / applicazioni che la consumano.

oAuth

Vado avanti e butto 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 andare a un browser Web) per l’autenticazione. Inoltre, non è ansible (sono a conoscenza) che il browser restituisca il callback all’applicazione (in particolare la multipiattaforma). Conosco un paio di app che lo fanno, ma è semplicemente sbagliato e dà un’interruzione nell’applicazione UX.

Requisiti

  1. L’utente immette nome utente / password nell’applicazione.
  2. Ogni chiamata API viene identificata dall’applicazione chiamante.
  3. L’overhead è ridotto al minimo e l’aspetto auth è 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 credenziali dell’applicazione non sono esposte).
  5. Se ansible, non richiedere https (in nessun caso un requisito severo).

I miei pensieri correnti sull’implementazione

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

  • apikey: assegnato allo sviluppatore alla regisrazione
  • timestamp – raddoppia come identificativo univoco per ogni messaggio per un determinato 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 / attenua gli attacchi di replay. L’hash garantisce che la richiesta sia stata effettivamente emessa dal proprietario della data chiave.

Per le richieste autenticate (quelle fatte per conto di un utente), sono ancora indeciso tra l’andare con una route access_token o una combinazione di hash username e password. In ogni caso, a un certo punto sarà richiesta una combinazione di nome utente / password. Quindi quando lo fa, un hash di diverse informazioni (apikey, apisecret, timestamp) + verrebbe usata la password. Mi piacerebbe un feedback su questo aspetto. Cordiali saluti, avrebbero dovuto hash prima la password, dal momento che non memorizzo le password nel mio sistema senza hash.

Conclusione

Cordiali saluti, questa non è una richiesta su come build / strutturare l’API in generale solo come gestire l’autenticazione e l’authorization esclusivamente all’interno di un’applicazione.

Pensieri casuali / Domande bonus

Per le API che richiedono solo un apikey come parte della richiesta, come impedire a qualcuno che non sia il proprietario di apikey di vedere l’apikey (poiché inviato in chiaro) e fare richieste eccessive per spingerli oltre i limiti di utilizzo? Forse sto solo pensando a questo, ma non dovrebbe esserci qualcosa per autenticare che una richiesta è stata verificata al proprietario di apikey? Nel mio caso, questo era lo scopo dell’apisecret, non viene mai mostrato / trasmesso senza essere sottoposto a hash.

A proposito di hash, che dire di md5 contro hmac-sha1? Ha davvero importanza quando tutti i valori sono sottoposti a hash con dati sufficientemente lunghi (ad esempio apisecret)?

In precedenza avevo pensato di aggiungere un hash per utente / riga salt 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?

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

  1. prima di accedere l’utente richiede un login_token dal server. Questi sono generati e memorizzati sul server su richiesta e probabilmente hanno una durata limitata.

  2. per accedere all’applicazione si calcola l’hash della password dell’utente, quindi si blocca la password con il login_token per ottenere un valore, quindi si restituiscono sia il login_token che l’hash combinato.

  3. Il server verifica che login_token sia uno che ha generato, rimuovendolo dal suo elenco di login_token validi. Il server quindi combina il suo hash memorizzato della password dell’utente con il login_token e assicura che corrisponda al token combinato inviato. Se corrisponde, hai autenticato il tuo utente.

I vantaggi di questo sono che non si memorizza mai la password dell’utente sul server, la password non viene mai passata in chiaro, l’hash della password viene passato solo nella creazione dell’account chiaro (anche se potrebbero esserci modi per aggirare questo), e dovrebbe essere sicuro da attacchi di replay quando il login_token viene rimosso dal DB in uso.

Sono un sacco di domande in una, credo che molte persone non siano riuscite a leggere fino alla fine 🙂

La mia esperienza nell’autenticazione dei servizi Web è che la gente di solito la ridefinisce e i problemi sono gli stessi che si incontrerebbero su una pagina web. Possibili opzioni molto semplici includerebbero https per il passo di accesso, restituire un token, richiedere che fosse incluso nelle richieste future. È anche ansible utilizzare l’autenticazione di base http e passare semplicemente i dati nell’intestazione. Per maggiore sicurezza, ruotare / espirare i token frequentemente, controllare che le richieste provengano dallo stesso blocco IP (questo potrebbe diventare complicato anche se gli utenti mobili si spostano tra le celle), combinandosi con la chiave API o simile. In alternativa, esegui il passaggio “request key” di oauth (qualcuno lo ha già suggerito in una risposta precedente ed è una buona idea) prima di autenticare l’utente e usarlo come chiave richiesta per generare il token di accesso.

Un’alternativa che non ho ancora usato, ma ne ho sentito parlare molto in quanto un’alternativa “friendly” ai dispositivi oAuth è xAuth . Dai un’occhiata e se lo usi allora sarei davvero interessato a sapere quali sono le tue impressioni.

Per l’hashing, sha1 è un po ‘meglio ma non si blocca – qualunque cosa i dispositivi possano facilmente implementare (e rapidamente in termini di prestazioni) probabilmente va bene.

Spero che ti aiuti, buona fortuna 🙂

Twitter ha affrontato il problema dell’applicazione esterna in oAuth supportando una variante chiamata xAuth . Sfortunatamente ci sono già una miriade di altri schemi con questo nome, quindi può essere fonte di confusione da risolvere.

Il protocollo è oAuth, tranne che salta la fase del token di richiesta e invia immediatamente una coppia di token di accesso al ricevimento di un nome utente e una password. (A partire dalla fase E qui .) Questa richiesta e risposta iniziale devono essere protette : inviano il nome utente e la password in testo semplice e ricevono il token di accesso e il token segreto. Una volta che la coppia di token di accesso è stata configurata, se lo scambio di token iniziale era 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 i requisiti impongano questo approccio.

In ogni caso, mi piacerebbe essere d’accordo con la tua intuizione e quella di molti altri rispondenti qui: non provare a build qualcosa di nuovo da zero. I protocolli di sicurezza possono essere facili da avviare, ma sono sempre difficili da fare bene e tanto più complicati diventano meno probabilità che gli 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, gli sviluppatori dovranno eseguire il rollover.

Quindi quello che cerchi è una sorta di meccanismo di autenticazione lato server che gestirà gli aspetti di autenticazione e authorization di un’applicazione mobile?

Supponendo che questo sia il caso, allora mi piacerebbe affrontarlo come segue (ma solo perche ‘sono uno sviluppatore Java quindi un C # guy lo farebbe diversamente):

Il servizio di autenticazione e authorization RESTful

  1. Funzionerà solo su HTTPS per impedire intercettazioni.
  2. Sarà basato su una combinazione di RESTEasy , Spring Security e CAS (per Single Sign-On su più applicazioni).
  3. Funzionerà con entrambi i browser e le applicazioni client abilitate al web
  4. Ci sarà un’interfaccia di gestione degli account basata sul web per consentire agli utenti di modificare i loro dettagli, e gli amministratori (per particolari applicazioni) di modificare i livelli di authorization

La libreria / applicazione di sicurezza lato client

  1. Per ogni piattaforma supportata (es. Symbian, Android, iOS ecc.) Creare un’adeguata implementazione della libreria di sicurezza nella lingua nativa della piattaforma (ad es. Java, ObjectiveC, C ecc)
  2. La libreria deve gestire la formazione delle richieste HTTPS utilizzando le API disponibili per la piattaforma indicata (ad esempio, Java utilizza URLConnection, ecc.)
  3. I consumatori della libreria di autenticazione e authorization generale (‘cos che è tutto ciò che è) codificheranno su un’interfaccia specifica e non saranno felici se cambierà così assicuratevi che sia molto flessibile. Segui le scelte progettuali esistenti come Spring Security.

Quindi ora che la vista da 30.000 piedi è completa, come si fa a farlo? Bene, non è così difficile creare un sistema di autenticazione e authorization 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 (solitamente 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 viene effettuata una richiesta.

Nel caso dell’applicazione mobile locale, sembra che tu stia cercando una soluzione che faccia quanto 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 il loro ACL consente solo l’accesso agli oggetti che hanno una Q nel loro nome, quindi alcuni dati nella raccolta vengono tirati in basso dall’interceptor di sicurezza. In Java questo è semplice, basta usare le annotazioni Spring Security sul codice chiamante e implementare un processo di risposta ACL adatto. In altre lingue, sei da solo e probabilmente dovrai fornire il codice di sicurezza che può essere chiamato 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 memoria privata per l’applicazione corrente in modo che non debba rimanere connesso. A seconda della durata della sessione di accesso, questa potrebbe essere un’operazione singola che non verrà mai ripetuta.

Qualunque cosa tu faccia, non provare a inventare il tuo protocollo di sicurezza , o usare 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. Pertanto, se affermi che la tua libreria di sicurezza fornisce l’authorization e l’autenticazione per le applicazioni mobili locali utilizzando una combinazione di token crittografati SSL, HTTPS, SpringSecurity e AES, avrai immediatamente credito nel mercato.

Spero che questo aiuti, e buona fortuna con la vostra impresa. Se desideri maggiori informazioni, fammi sapere – Ho scritto un bel po ‘di applicazioni web basate su Spring Security, ACL e simili.

Super tardi alla festa ma volevo inserire alcuni punti aggiuntivi da considerare per chiunque fosse interessato a questo problema. Lavoro per un’azienda che fa soluzioni di sicurezza API mobili ( approov ), quindi l’intera area è decisamente pertinente ai miei interessi.

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

Nella soluzione proposta si menziona che saranno richiesti almeno tre parametri:

  • apikey: assegnato allo sviluppatore alla registrazione
  • timestamp – raddoppia come identificativo univoco per ogni messaggio per un determinato apikey
  • hash – un hash del timestamp + l’apisecret

L’implicazione di ciò è che per alcune chiamate API non è richiesto alcun nome utente / password. Questo può essere utile per le applicazioni in cui non si desidera forzare un accesso (ad esempio nei negozi online).

Questo è un problema leggermente diverso da quello di autenticazione dell’utente ed è più simile all’autenticazione o all’attestazione del software. Non c’è un utente, ma vuoi comunque assicurarti che non ci sia un accesso malevolo alla tua API. Quindi utilizzi il tuo segreto API per firmare il traffico e identificare il codice che accede all’API come originale. Il potenziale problema con questa soluzione è che devi dare via il segreto all’interno di ogni versione dell’app. Se qualcuno può estrarre il segreto, può usare la tua API, impersonare il tuo software ma fare quello che vuole.

Per contrastare questa minaccia ci sono un sacco di cose che puoi fare a seconda del valore dei dati. L’offuscamento è un modo semplice per rendere più difficile l’estrazione del segreto. Ci sono strumenti che lo faranno per te, più ancora per Android, ma devi ancora avere il codice che genera il tuo hash e un individuo sufficientemente qualificato può sempre chiamare la funzione che esegue direttamente l’hashing.

Un altro modo per mitigare l’uso eccessivo di un’API che non richiede un accesso è limitare il traffico e potenzialmente identificare e bloccare gli indirizzi IP sospetti. La quantità di sforzi a cui vuoi andare dipenderà in gran parte dalla valenza dei tuoi dati.

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