Come salvaguardare un'API REST solo per applicazioni mobili attendibili


96

Come posso assicurarmi che l'API REST risponda solo alle richieste generate da client fidati, nel mio caso le mie applicazioni mobili? Voglio prevenire richieste indesiderate provenienti da altre fonti. Non voglio che gli utenti inseriscano una chiave seriale o altro, dovrebbe accadere dietro le quinte, al momento dell'installazione e senza alcuna interazione da parte dell'utente.

Per quanto ne so, HTTPS è solo per convalidare il server con cui stai comunicando è chi dice di essere. Ovviamente userò HTTPS per crittografare i dati.

C'è un modo per raggiungere questo obiettivo?

Aggiornamento: l'utente può eseguire azioni di sola lettura, che non richiedono che l'utente abbia effettuato l'accesso, ma può anche eseguire azioni di scrittura, che richiedono l'accesso dell'utente (autenticazione tramite token di accesso). In entrambi i casi, desidero che l'API risponda alle richieste provenienti solo da applicazioni mobili affidabili.

L'API verrà utilizzata anche per la registrazione di un nuovo account tramite l'applicazione mobile.

Aggiornamento 2: sembra che ci siano più risposte a questo, ma sinceramente non so quale contrassegnare come risposta. Alcuni dicono che può essere fatto, altri dicono che non può.


HTTPS utilizza SSL (e TLS). SSL / TLS può essere utilizzato con l'autenticazione client.
atk,

Intendi i certificati SSL lato client? Penso che sia quello che sto cercando, tranne per il fatto che non ho idea se ciò sia possibile anche nelle applicazioni mobili (Android e iOS)? Dove sarebbe archiviato il certificato client? Memoria del dispositivo, memoria?
Supercell

SSL certificherà solo il dispositivo mobile, NON l'applicazione mobile.
Morons,

@Supercell: aggiungerò una risposta
atk

Risposte:


48

Non puoi.

Non puoi mai verificare un'entità, qualsiasi entità , che sia una persona, un client hardware o un client software. Puoi solo verificare che ciò che ti stanno dicendo sia corretto, quindi assumere l'onestà .

Ad esempio, come fa Google a sapere se sto accedendo al mio account Gmail? Semplicemente mi chiedono per un nome utente e una password, verificare che , quindi assumere l'onestà , perché chi altro avrebbe avuto queste informazioni? Ad un certo punto Google ha deciso che ciò non era sufficiente e ha aggiunto la verifica comportamentale (alla ricerca di comportamenti strani) ma che si basa ancora sulla persona per eseguire il comportamento , quindi convalidare il comportamento .

Questa è esattamente la stessa cosa con la convalida del cliente. Puoi solo validare il comportamento del Cliente, ma non il Cliente stesso.

Quindi, con SSL, puoi verificare che il client abbia un certificato valido o meno, quindi puoi semplicemente installare l'app, ottenere il certificato, quindi eseguire tutto il nuovo codice.

Quindi la domanda è: perché è così critico? Se questa è una vera preoccupazione, metterei in dubbio la tua scelta di un cliente grasso. Forse dovresti andare con un'app Web (quindi non devi esporre la tua API).

Vedi anche: Sconfiggere la convalida del certificato SSL per le applicazioni Android

e: quanto sono sicuri i certificati SSL client in un'app mobile?


1
Ho usato i certificati client su hardware in cui il certificato è stato archiviato su un'unità crittografata dal sistema operativo. Ma anche lì, nessuno credeva che fosse infallibile. L'obiettivo era solo quello di rendere difficile per gli utenti occasionali.
Steven Burnap,

1
@Morons: una webapp risolverebbe questo problema, ma pensiamo che gli utenti avranno più probabilità di utilizzare l'app nativa rispetto a una webapp (correggimi se la nostra ipotesi è errata). Il motivo per cui questo è così critico è perché l'API offre all'utente l'accesso a parti del nostro database, che contiene molti dati raccolti durante mesi di lavoro. Si tratta di dati che altre aziende o utenti potrebbero utilizzare facilmente per i propri scopi. Senza proteggere i clienti, non sapremmo chi lo stava usando (contro di noi).
Supercell

6
Una webapp non risolve il problema. È abbastanza banale modificare qualsiasi webapp lato client e farlo fare quello che vuoi.
Steven Burnap,

5
@Supercell Non puoi mostrare a qualcuno i dati e poi impedire loro di condividerli. Se non desideri che alcuni dispongano di dati, non li dai (mostrali) a loro.
Morons,

Sono d'accordo ma per motivi diversi. Puoi farlo se avessi il controllo dei dispositivi, rsa è come en.wikipedia.org/wiki/SecurID . Ma i cellulari non sono qualcosa che può essere controllato (potrebbero accettare l'allegato come una chiave del plugin o qualcosa del genere).
imel96,

31

Sono sicuro che hai dimestichezza con la gestione degli accessi degli utenti e con le comunicazioni su SSL, quindi mi concentrerò su ciò che ritengo sia la parte più interessante della domanda: come garantire che le tue azioni di sola lettura - che non richiedono l' autenticazione dell'utente - sono accettati solo dalle tue app client?

Prima di ogni altra cosa, c'è il rovescio della medaglia a cui fNek ha accennato in una risposta precedente: le tue app client sono nelle mani di utenti potenzialmente ostili. Possono essere esaminati, le loro comunicazioni controllate, il loro codice smontato. Nulla che sto per suggerire ti consentirà di garantire che qualcuno non decodifichi il tuo client e non abusi dell'API REST. Ma dovrebbe mettere una barriera di fronte a qualsiasi tentativo casuale.

Ad ogni modo, un approccio comune è:

  • Il client contiene un segreto
  • Quando si effettua una richiesta, concatena i parametri della richiesta con i segreti e esegue l'hashing del risultato
  • Questo hash viene inviato con la richiesta e verificato dal server

ad esempio, immaginare una GETrichiesta per/products/widgets

Supponiamo che il segreto del client sia "OH_HAI_I_IZ_SECRET"

Concatena il verbo HTTP, l'URL e il segreto:

GET/products/widgetsOH_HAI_I_IZ_SECRET

E prendi un hash SHA-1 di quello:

4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Quindi invialo insieme, quindi la richiesta sarebbe per:

GET /products/widgets?hash=4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Infine, per impedire a qualcuno di riprodurre almeno le singole richieste, prendi anche un timestamp e aggiungilo ai parametri e all'hash. es. proprio ora, in tempo Unix, è 1384987891. Aggiungilo alla concatenazione:

GET/products/widgetsOH_HAI_I_IZ_SECRET1384987891

Hash che:

2774561d4e9eb37994d6d71e4f396b85af6cacd1

E invia:

GET /products/widgets?time=1384987891&hash=2774561d4e9eb37994d6d71e4f396b85af6cacd1

Il server verificherà l'hash e verificherà anche che il timestamp sia corrente (ad es. Entro 5 minuti per consentire che gli orologi non siano perfettamente sincronizzati)

Avvertimento! Dal momento che stai parlando di app mobili, c'è il rischio che il telefono di qualcuno abbia l'orologio sbagliato. O fuso orario sbagliato. O qualcosa. L'aggiunta di tempo all'hash probabilmente interromperà alcuni utenti legittimi, quindi usa questa idea con cautela.


6
questo meccanismo di hashing può essere compreso da qualsiasi programmatore quando smonta l'apk.
Punith Raj,

8
@PunithRaj esattamente, l'ho trattato nel secondo paragrafo. "Nulla che sto per suggerire ti consentirà di garantire che qualcuno non decodifichi il tuo client e non abusi dell'API REST. Ma dovrebbe mettere una barriera di fronte a qualsiasi tentativo casuale."
Carson63000,

per l'avvertenza, sto usando UTC su server e mobile, questo risolve il problema, giusto?
Shareef

@ Carson63000 - quindi, c'è una soluzione concreta? soprattutto per l'API di registrazione dell'utente, che deve essere aperta pubblicamente (un utente deve registrarsi prima di poter accedere, sul Web o su un'app mobile) e può essere scelto come target dai robot per creare migliaia di utenti falsi.
Tohid

17

Per chiunque sia interessato, su Android PUOI verificare che la richiesta che hai ricevuto sia stata inviata dalla tua app.

In breve, quando carichi la tua app su google la firmi, con una chiave univoca nota solo a te (e google).

Il processo di verifica procede (ish) in questo modo:

  1. la tua app va su google e richiede il token di autenticazione
  2. l'app invia il token in modo sicuro al back-end
    1. il tuo back-end va su google e controlla il token di autenticazione ottenuto dalla tua app.
    2. il tuo back-end controlla quindi se la chiave univoca che la tua app ha firmato corrisponde, altrimenti significa che non era la tua app ...

il blog completo che lo spiega e come implementarlo può essere trovato qui: http://android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-android.html


1
Buona risposta, tuttavia un utente malintenzionato può ancora falsificare un'app con sufficiente sforzo. ma nulla è veramente sicuro, non è una questione di se, solo una questione di quando
mateos

1
Per iOS esiste questa opzione: link Le API DeviceCheck ti consentono anche di verificare che il token che ricevi provenga da un dispositivo Apple autentico su cui è stata scaricata la tua app
Iwaz,

Richiede account (e-mail)
utente25

5

Ok, quindi vale la pena menzionare prima di iniziare che per la maggior parte delle applicazioni questo è enormemente eccessivo. Per la maggior parte dei casi di utilizzo, avere semplicemente un singolo certificato e / o token valido è più che sufficiente. Se si tratta di fare qualcosa di difficile come decompilare la tua app, anche la maggior parte degli hacker non si preoccuperà a meno che tu non fornisca alcuni dati molto preziosi. Ma hey, dov'è il divertimento in quella risposta?

Quindi quello che puoi fare è impostare la crittografia asimmetrica in qualche modo come la firma digitale usata per firmare i programmi. Ogni app può quindi disporre di un singolo certificato emesso da una singola CA e verificato quando l'utente si connette. (alla prima registrazione o alla prima installazione) Quando il certificato viene autenticato, è possibile proteggere ulteriormente l'applicazione registrando quel certificato come valido per un determinato identificatore del dispositivo (come l' ID Android )


5

Come menzionato da @Morons nella sua risposta, è molto difficile verificare l'entità all'altro capo della connessione.

Il modo più semplice per fornire un certo livello di autenticità è fare in modo che il server controlli alcuni segreti che solo l'entità reale potrebbe conoscere. Per un utente, potrebbe essere un nome utente e una password. Per un software in cui non è presente alcun utente, è possibile incorporare un segreto.

Il problema con questi approcci è che devi fidarti del cliente. Se qualcuno esegue il reverse engineering della tua app o ruba la tua password, può fingere di essere tu.

Puoi prendere delle misure per rendere più difficile l'estrazione delle informazioni segrete offuscandole nell'eseguibile. Strumenti come ProGuard, che è un offuscatore per Java, possono aiutare in questo, non so molto dell'offuscamento in altre lingue, ma probabilmente esistono strumenti simili. L'uso di una connessione TLS aiuta a prevenire ficcanaso nel traffico, ma non impedisce un attacco MITM. Il pinning può aiutare a risolvere questo problema.

Lavoro per un'azienda chiamata CriticalBlue (divulgazione completa!) Che ha un prodotto chiamato Approov che cerca di affrontare questo problema di fiducia. Funziona attualmente per Android / iOS e fornisce un meccanismo ai nostri server per verificare l'integrità dell'app client. Lo fa portando il cliente a calcolare una risposta a una sfida casuale. Il client deve calcolare la risposta utilizzando gli attributi del pacchetto dell'app installato che sono difficili da falsificare e include alcuni sofisticati meccanismi anti-manomissione.

Restituisce un token che puoi quindi inviare come prova di autenticità alla tua API.

La differenza importante con questo approccio è che, sebbene sia possibile disabilitare il controllo di autenticità sul client, in tal caso non si otterrebbe il token di autenticazione, è necessario verificare l'app con il server. La libreria è anche strettamente accoppiata alle caratteristiche dell'eseguibile in cui si trova, quindi sarebbe molto difficile incorporarla in un'app falsa e farla funzionare.

Esiste un'analisi costi / benefici che qualsiasi sviluppatore di API deve fare per decidere con quale probabilità qualcuno tenterà di hackerare la propria API e quanto costoso possa essere. Un semplice controllo segreto nell'applicazione impedisce attacchi insignificanti, ma proteggersi da un aggressore più determinato è probabilmente considerevolmente più complicato e potenzialmente costoso.


0

SSL proteggerà il canale di comunicazione.

L'accesso riuscito emetterà un token di autenticazione su una connessione crittografata.

Il token di autenticazione verrà passato all'API REST in tutte le richieste successive.


1
Ho aggiunto alcune informazioni aggiuntive. Avevo intenzione di fare l'autenticazione come hai menzionato, con un token di accesso. L'API REST non richiede che l'utente abbia effettuato l'accesso, ma solo per azioni specifiche. In entrambi i casi, i client devono essere firmati / attendibili.
Supercell

Non so molto sullo sviluppo mobile nativo, ma la tua applicazione mobile può fornire il numero mobile all'API REST? Quando installo app sul mio telefono Android, mi viene spesso chiesto di concedere determinate autorizzazioni all'app. Se puoi inviare un numero di cellulare con ogni richiesta tramite una connessione protetta, puoi rifiutare tutte le richieste con un numero di cellulare sconosciuto.
Sto

Potrebbe funzionare, ma richiederebbe l'accesso dell'utente e il numero associato all'account utente. Altrimenti il ​​server non avrebbe nulla per verificare il numero.
Supercell

Come installerai la tua applicazione mobile?
CodeART

Saranno disponibili tramite gli app store (Google, Apple, Microsoft)
Supercell

0

Non sarebbe troppo sicuro, ma potresti aggiungere una sorta di codice segreto o persino una firma digitale. Unico inconveniente: deve essere incluso nell'app, il che rende facile ottenerlo se sai cosa fai.


0

Per quanto ne so, HTTPS è solo per convalidare il server con cui stai comunicando è chi dice di essere.

In effetti, è possibile utilizzare SSL per autenticare sia il client che il server. Oppure, indicato in modo diverso, "sì, è possibile utilizzare i certificati client".

Dovrai ...

  • guarda la libreria SSL che stai utilizzando per determinare come specificare i certificati client nel dispositivo mobile,
  • scrivere il codice o configurare il server HTTPS in modo che accetti solo connessioni da client registrati affidabili.
  • elaborare un meccanismo per aggiungere certificati client attendibili nel server
  • elaborare un meccanismo per rimuovere i certificati client non più attendibili dal server

Puoi fare in modo che l'applicazione mobile memorizzi il certificato dove vuoi. Dal momento che la si desidera autenticazione specifica dell'applicazione, è necessario considerare la memorizzazione del certificato in una posizione del disco protetta (su Android, è possibile creare una tabella "config" nel database SQLite e una riga per il certificato e un'altra per la chiave privata) .

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.