19

Quando si progetta un iOS app che interagirà con AWS (ad esempio S3, CloudFront, ecc), quali sono i pro ei contro di gestione l'accesso a questi servizi sul client vs sul server?Gestione dell'accesso ai servizi AWS su iOS client vs sul server di backend

Con "gestione dell'accesso", intendo cose come caricare contenuti privati ​​su S3, scaricare contenuti privati ​​tramite Cloudfront.

Ovviamente, qualsiasi lato che gestisca l'accesso dovrà memorizzare la chiave di accesso AWS e l'accesso segreto. La sicurezza è una delle preoccupazioni.

Sono ugualmente interessato all'impatto di questa scelta di progettazione sulle prestazioni e sulla flessibilità di entrambe le implementazioni.

Infine, c'è un argomento per l'implementazione di un approccio ibrido in cui sia client che server interagiscono direttamente con AWS oppure l'implementazione di solito va con uno o l'altro, ma non con entrambi?

risposta

10

Mentre ci sono molti scenari in cui si potrebbe desiderare di fare questo in entrambi i casi, in generale, ci sono pochissime casi in cui si vorrebbe farlo direttamente dal client poiché si parla di iOS:

Pro per il caricamento dei dati via lato server per AWS:

  1. Security

    Come già accennato in altra risposta, avendo richieste autenticate inizialmente si risparmierebbe molto fastidio dai miscredenti e gli hacker se stanno cercando di rompere roba giù . Se i dati sono privati ​​e si è veramente impegnati per la privacy, qualsiasi perdita di dati sarebbe più facile da prevenire se il sistema è autenticato.

  2. Rate limiting, quote utente, ecc

    il vantaggio di sistemi autenticati è che si può votare limitare le richieste provenienti da fonti particolari, diciamo utente, gruppo, quote ecc (livello applicazione IP se si intende costruire più app sulla stessa architettura di sistema). Costruire questa intelligenza non è così facile quando si lavora direttamente sul lato client.

  3. Pista di controllo

    Se hai bisogno di tenere traccia di chi caricato cosa, quando, da dove, e più queste informazioni, questo è ancora una volta molto più facile per tenere traccia se si ottiene la richiesta iniziale direttamente sul vostro server .

  4. movimentazione in caso di fallimento

    eccezione è del tutto possibile avere fallimenti che non si avrebbe facilmente previsto, o manca un bug critico durante i test QA. Gestire questi server è molto più efficiente, perché è sotto il tuo controllo. Quando sorgono problemi di questo tipo da parte del cliente, sei in balia dei tuoi clienti che sono in grado di aggiornare l'app. Se si ha a che fare con questo lato server, possono essere facilmente posizionati/implementati controlli aggiuntivi per molti di questi bug, limitando la portata del bug.

  5. È ora di andare in diretta

    Anche in questo caso, come indicato nel altra risposta, si può prendere un po 'prima che l'aggiornamento è stato approvato. Questo porta notevolmente il vostro risposta alle criticità, e può essere difficile da ridurre, in caso di problemi gravi (perdita di dati/violazione della privacy) che portano a perdite significative (la fiducia finanziaria/user/feedback negativi etc)

Il solo i casi in cui penso che si vorrebbe caricare i dati direttamente dal lato client per AWS sarebbe

  • caricare grandi quantità di dati, molto, molto frequentemente, senza elaborazione diretta.

    Se il caricamento una volta costa una certa quantità di larghezza di banda e risorse di rete, caricarlo due volte raddoppia le risorse (una volta da client --> server, quindi da server --> AWS). Quindi, se carichi una grande quantità di dati frequentemente (pensi TBs al giorno), allora finisci per sprecare molte delle tue risorse semplicemente copiando i dati da un punto a un altro. In questi casi, ha senso spingere i dati direttamente S3. Ma perché questo approccio funzioni, i tuoi risparmi dovrebbero essere abbastanza alti da superare le preoccupazioni sulla sicurezza e sulla privacy e, per la maggior parte delle applicazioni, semplicemente non è così.

  • Sei in un giardino recintato

    In sostanza, l'applicazione funziona solo per alcuni utenti di pre-identificati, l'applicazione semplicemente non funziona per chiunque altro (dire che si stavano sviluppando questo per l'uso in casa in un aziendale). In sostanza, questo significa avere una fiducia al 100% nei motivi per l'utente finale di utilizzare la tua app.


EDIT: OP chiede nei commenti

Come su server che fornisce firmato URL/biscotti, e il client utilizza questi per caricare S3 o scaricare da Cloudfront. Il client interagisce ancora direttamente con AWS ma richiede le autorizzazioni controllate dal server.

A prima vista, mi sembra molto praticabile.Questo blog post fornisce molti casi d'uso (come la fornitura di URL con caratteri jolly per la lettura) intorno all'uso di URL firmati (sebbene gli esempi siano in .NET) e ulteriori informazioni siano disponibili allo AWS docs.

Dal momento che si gestirà il lato server di firma, si può facilmente occuparsi di ciascuno dei punti che ho menzionato in precedenza nel mio post (limitazione della velocità, quote utente, audit trail ecc è tutto praticabile, dal momento che la richiesta inizialmente vai al server). Come this answer menzioni,

Gli URL di firma consentono di controllare chi può accedere a un determinato file e per quanto tempo possono accedervi.

Nel complesso, questo dovrebbe funzionare bene per diversi casi d'uso.

+0

Informazioni sul server che fornisce URL/cookie firmati e il client li utilizza per caricare su S3 o scaricare da Cloudfront. Il client interagisce ancora direttamente con AWS ma richiede le autorizzazioni controllate dal server. Puoi commentare questa strategia? – skyork

+0

@skyork Non penso che sarà molto efficace, controlla le modifiche. –

+0

Non sono sicuro che la modifica relativa agli URL firmati sia corretta. Gli URL firmati non devono necessariamente essere non firmati dal client in questo caso, il client utilizza semplicemente questi URL come dati a 'PUT' o' GET' dalle risorse AWS. E puoi impostare un tempo di scadenza su questi URL in modo che il cliente non possa accedere alla risorsa AWS dopo la scadenza. Apprezzo i tuoi altri punti. – skyork

3

La sicurezza è la ragione principale per cui inserire/la maggior parte dell'autenticazione del servizio AWS sul back-end dopo aver autenticato l'utente.

Un'altra considerazione è la quantità di tempo necessaria per aggiornare la tua applicazione su Apple Store data la procedura di approvazione. Possono essere necessari giorni in base alla coda di Apple Store per poter inviare modifiche alla tua app; le modifiche sul back-end di AWS possono essere fatte a volontà.

Inoltre, nel progettare un'app per interagire con i servizi AWS, presumo sempre che qualsiasi cosa trasmessa possa essere compromessa e molto probabilmente verrà utilizzata da persone che hanno decostruito le chiamate e ricostruito le proprie per soddisfare le loro esigenze.

(Ad esempio, poco dopo l'avvio di un'applicazione di intrattenimento fotografico che carica le immagini e quindi applica i filtri, abbiamo notato voci di registro con ID di filtro che non esistevano nell'app provenienti dallo stesso IP. non è stato autenticato.)

Spero che questo aiuti.

+0

grazie per il vostro input. Il momento di aspettare l'approvazione degli app store è un buon punto. Per quanto riguarda l'aspetto della sicurezza, non è vero che qualcuno deve decompilare la tua app iOS e quindi utilizzare le credenziali AWS per accedere alle tue risorse AWS? Senza fare ciò, c'è qualcos'altro dannoso che si possa fare con un'app per iOS che incorpora le credenziali di AWS e interagisce direttamente con AWS? – skyork

+0

Senza dire troppo sulla sicurezza, la cosa più semplice da fare per qualcuno è semplicemente tracciare la rete tra il telefono e qualsiasi servizio o server utilizzato. –

3

In aggiunta alle altre buone risposte, vorrei aggiungere un ulteriore punto: a differenza delle app Web, non è possibile aspettarsi che tutti gli utenti dispongano della versione più recente della propria app. Ciò significa che qualsiasi URL del server che qualsiasi versione della tua app ha mai chiamato deve, in linea di principio, rimanere in diretta per sempre. Ciò significa che se vuoi cambiare la tua infrastruttura di server lungo la strada (es. Migrare da AWS ad un altro host cloud), allora non puoi perché anche se crei una versione aggiornata della tua app con nuovi URL, allora ci sarà ancora alcune app non aggiornate che chiamano i vecchi URL.

Ovviamente si può scegliere di fare un "aggiornamento forzato" meccanismo in app in cui non è possibile utilizzare fino a quando si aggiorna (questo è comune nei giochi multiplayer, ma non molti altri luoghi) o semplicemente non prenditi cura di una minoranza di utenti di vecchie versioni della tua app di cui ti rendi infelice (trama distorta - potrebbero essere bloccati su una vecchia versione della tua app perché il loro dispositivo non può essere aggiornato alla versione più recente di iOS).

Ma la soluzione migliore IMO è nascondere gli URL AWS dietro i propri server, in modo da non incorrere mai in questo problema. È un dettaglio di implementazione che non dovresti assolutamente presentare nel client.

2

Per motivi di sicurezza, è importante tenere le chiavi in ​​un posto dove non possono essere manomesse: in genere significa lasciarle sul server.

Pensa alle tue chiavi in ​​questo modo: concedono l'accesso alle risorse della tua organizzazione. Inserendo le chiavi su un dispositivo mobile, il furto delle chiavi influisce sulle risorse a livello dell'organizzazione. Utilizza invece l'autenticazione a livello utente sul dispositivo mobile per concedere l'accesso alla risorsa AWS tramite un proxy sui tuoi server. In questo modo, la perdita di credenziali a livello di utente non comporta perdite a livello di organizzazione ed è più facile revocare le credenziali a livello di utente.

Si menzionano anche gli upload su S3. AWS ha una bella funzione chiamata post in cui il tuo server genera credenziali di caricamento una tantum che il tuo dispositivo mobile può utilizzare per caricare i dati su S3, senza effettuare il proxy dei dati attraverso il tuo server.

Esempio codice Ruby:

presigned_post = bucket.presigned_post(key: key, success_action_status: 201, acl: :public_read)